On 09.03.2022 00:45, Pietro Convalle wrote:
Si, probabilmente la cosa migliore e' ridefinire __new__

ma invece di aggiungerla dopo la creazione prova ad aggiungerla durante
la creazione concatenando i valori default prima o dopo il for

ho anche provato ad aggiungere questa modifica dopo la creazione di
Links, ma non ha effetto.

Links._field_defaults = {
    cardinal_point.value: None
    for cardinal_point in CARDINAL_POINTS_6_NS
}

suppongo che provare a ridefinire __new__ possa essere la
soluzione...

Incuriosito dalla tua domanda e curioso di scoprirne di più su Python3
ho investigato sull'implementazione di typing.NamedTyple.

Non sono sicuro questo sia una buona soluzione per la ragione che accedo
ad un attributo privato del modulo typing. In aggiunta, anche se non
conosco il contesto e non è questo quello che hai chiesto, mi domando se
avere una classe dinamica sia una buona soluzione. Come linea di
principio ritengo le meta-classi qualcosa da evitare e spesso si hanno
delle soluzioni più semplici.

Questo è un utilizzo tradizionale di typing.NamedTyple:

    $ python3.10
Python 3.10.2 (main, Feb 15 2022, 12:33:54) [GCC 10.2.1 20210110] on linux Type "help", "copyright", "credits" or "license" for more information.
    >>> import typing
    >>> class Point(typing.NamedTuple):
    ...  x: int
    ...  y: int = 0
    ...
    >>> Point.__annotations__
    {'x': <class 'int'>, 'y': <class 'int'>}
    >>> Point.y
    _tuplegetter(1, 'Alias for field number 1')
    >>> Point.x
    _tuplegetter(0, 'Alias for field number 0')

Il primo tentativo è stato quello di utilizzare type per create
dinamicamente una classe. Questo non ha funzionato, ma conosco troppo
poco le annotations e tutto quello che ne ha derivato per dare un
qualche commento.

>>> Point2 = type('Point2', (typing.NamedTuple, ), {'__annotations__': {'x': int, 'y': int}, 'y': 2})
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
TypeError: type() doesn't support MRO entry resolution; use types.new_class()

Come consigliato dal messaggio di errore ho provato ad utilizzare
types.new_class, ma questa non permette di definire gli attributi della
nuova classe, necessari per definire i valori di default.


    >>> import types
>>> Point2 = types.new_class('Point2', (typing.NamedTuple, ), {'__annotations__': {'x': int, 'y': int}, 'y': 2})
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
File "/home/marco/.pyenv/versions/3.10.2/lib/python3.10/types.py", line 77, in new_class
        return meta(name, resolved_bases, ns, **kwds)
TypeError: NamedTupleMeta.__new__() got an unexpected keyword argument '__annotations__'

Il terzo tentativo è stato quello di chiamare la meta-classe
direttamente. Ottengo il risultato voluto, ma come vedi devo accedere
ad un attributo privato. Non sono sicuro perché NamedTupleMeta verifica
le classi basi, ma non neanche compito mio domandarmi perché.

>>> Point2 = typing.NamedTupleMeta('Point2', (typing._NamedTuple, ), {'__annotations__': {'x': int, 'y': int}, 'y': 2, '__module__': '__main__'})
    >>> Point2
    <class '__main__.Point2'>
    >>> Point2()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
TypeError: Point2.__new__() missing 1 required positional argument: 'x'
    >>> Point2(1)
    Point2(x=1, y=2)
    >>>



_______________________________________________
Python mailing list
Python@lists.python.it
https://lists.python.it/mailman/listinfo/python

Rispondere a