Questo è un altro caso delle pylint
regole cieche di S.
"Le classi non hanno lo scopo di memorizzare dati" - questa è una dichiarazione falsa. I dizionari non vanno bene per tutto. Un membro dati di una classe è qualcosa di significativo, un elemento del dizionario è qualcosa di opzionale. Prova: puoi fare dictionary.get('key', DEFAULT_VALUE)
per prevenire un KeyError
, ma non è semplice __getattr__
con predefinito.
MODIFICA: modi consigliati per utilizzare gli struct
Devo aggiornare la mia risposta. In questo momento, se hai bisogno di un struct
, hai due ottime opzioni:
a) Basta usare attrs
Questa è una libreria per questo:
https://www.attrs.org/en/stable/
import attr
@attr.s
class MyClass(object): # or just MyClass: for Python 3
foo = attr.ib()
bar = attr.ib()
Cosa ottieni in più: non scrivere costruttori, valori predefiniti, convalida, __repr__
oggetti di sola lettura (da sostituire namedtuples
, anche in Python 2) e altro.
b) Usa dataclasses
(Py 3.7+)
Seguendo il commento di hwjp, consiglio anche dataclasses
:
https://docs.python.org/3/library/dataclasses.html
Questo è quasi buono quanto attrs
, ed è un meccanismo di libreria standard ("batterie incluse"), senza dipendenze extra, tranne Python 3.7+.
Resto della risposta precedente
NamedTuple
non è eccezionale - specialmente prima di python 3 typing.NamedTuple
:
https://docs.python.org/3/library/typing.html#typing.NamedTuple
- dovresti assolutamente controllare il NamedTuple
pattern "class derivato da ". Python 2 - namedtuples
creato da descrizioni di stringhe - è brutto, cattivo e stupido "programmare all'interno di stringhe letterali".
Sono d'accordo con le due risposte attuali ("considera di usare qualcos'altro, ma pylint non è sempre giusto" - quella accettata, e "usa il commento di soppressione pylint"), ma ho il mio suggerimento.
Lasciatemelo sottolineare ancora una volta: alcune classi sono pensate solo per memorizzare i dati.
Ora l'opzione da considerare anche - usa property
-ies.
class MyClass(object):
def __init__(self, foo, bar):
self._foo = foo
self._bar = bar
@property
def foo(self):
return self._foo
@property
def bar(self):
return self._bar
Sopra hai proprietà di sola lettura, che va bene per Value Object (ad es. Come quelli in Domain Driven Design), ma puoi anche fornire setter: in questo modo la tua classe sarà in grado di assumersi la responsabilità dei campi che hai, ad esempio per fare un po 'di convalida ecc. (se hai setter, puoi assegnarli usandoli nel costruttore, cioè self.foo = foo
invece che direttamente self._foo = foo
, ma attenzione, i setter possono presumere che altri campi siano già inizializzati, e quindi hai bisogno di una validazione personalizzata nel costruttore) .