Attualmente sovrascrivo classe __setattr__
() verso la fine della classe __init__
() per evitare che nuova creazione attributo -Come scrivere metaclassi che impedirebbe di creare nuovi attributi dopo __init __()?
class Point(object):
def __init__(self):
self.x = 0
self.y = 0
Point.__setattr__ = self._setattr
def _setattr(self, name, value):
if not hasattr(self, name):
raise AttributeError("'" + name + "' not an attribute of Point object.")
else:
super(Point, self).__setattr__(name, value)
C'è un modo per evitare manualmente l'override __setattr__
() e farlo automaticamente con l'aiuto di metaclassi?
Il più vicino mi è venuto è stato -
class attr_block_meta(type):
def __new__(meta, cname, bases, dctry):
def _setattr(self, name, value):
if not hasattr(self, name):
raise AttributeError("'" + name + "' not an attribute of " + cname + " object.")
object.__setattr__(self, name, value)
dctry.update({'x': 0, 'y': 0})
cls = type.__new__(meta, cname, bases, dctry)
cls.__setattr__ = _setattr
return cls
class ImPoint(object):
__metaclass__ = attr_block_meta
Esiste un modo più generico di fare questo in modo tale che a priori la conoscenza della sottoclasse attributi non è necessario?
In pratica, come evitare la riga dctry.update({'x': 0, 'y': 0})
e farlo funzionare indipendentemente da quali siano i nomi degli attributi di classe?
P.S. - FWIW Ho già valutato le opzioni __slots__
e namedtuple e le ho trovate carenti per le mie esigenze. Per favore non restringere la tua attenzione all'esempio Punti() ridotto che ho usato per illustrare la domanda; il caso d'uso reale coinvolge una classe molto più complessa.
Perché? In quali circostanze qualcuno aggiungerebbe un attributo alla tua classe? Come autore di classe, come ti influenzerebbe? Come dice la massima, "siamo tutti adulti consenzienti" nella terra di Python; in questo caso significa che se violento la classe API aggiungendo un attributo, sono responsabile per eventuali conseguenze. Python non è Java né C++. – msw
@msw - Principalmente per individuare gli errori che riguardano gli errori di battitura APPENA POSSIBILE. Se potessi evitare che i programmatori digitassero accidentalmente _obj.staet_ e poi si chiedessero perché la macchina a stati funzionasse in modo irrequieto, allora lo farei. Fondamentalmente, vorrei ridurre il tempo che intercorre tra l'errore di battitura e la realizzazione finale. –
In Python non si può davvero usare la lingua per forzare il comportamento. Questo è uno dei motivi per cui test e recensioni di codice sono ancora più critici in Python. Diciamo che prendi il caso 'obj.staet' che descrivi, che ne dici di' ojb.state' e quando ti fermi. Le persone possono (e vogliono) scrivere codice spezzato in qualsiasi lingua ed è difficile proteggerle da se stesse. Infine, sei già protetto dalla metà dei problemi di "staet': fare riferimento a un oggetto' if obj.staet == 5: 'genererà un NameError; assignment 'obj.staet = 6' non verrà catturato da Python. – msw