È possibile inizializzare il dizionario di classe tramite il costruttore:
def __init__(self,**data):
e chiamarlo come segue:
f = MyClass(**{'a': 'v1', 'b': 'v2'})
Tutti dell'istanza attributi cui si accede (leggi) in __setattr__, hanno bisogno di essere dichiarato utilizzando il suo metodo parent (super), solo una volta:
super().__setattr__('NewVarName1', InitialValue)
O
super().__setattr__('data', dict())
Successivamente, si può accedere o assegnati nel solito modo:
self.data = data
E istanza attributi non essere accessibili in __setattr__, può essere dichiarato nel modo usuale:
self.x = 1
Il metodo __setattr__ sottoposto a override deve ora chiamare il metodo genitore al suo interno, affinché vengano dichiarate nuove variabili:
super().__setattr__(key,value)
Una classe completo apparirebbe come segue:
class MyClass(object):
def __init__(self, **data):
# The variable self.data is used by method __setattr__
# inside this class, so we will need to declare it
# using the parent __setattr__ method:
super().__setattr__('data', dict())
self.data = data
# These declarations will jump to
# super().__setattr__('data', dict())
# inside method __setattr__ of this class:
self.x = 1
self.y = 2
def __getattr__(self, name):
# This will callback will never be called for instance variables
# that have beed declared before being accessed.
if name in self.data:
# Return a valid dictionary item:
return self.data[name]
else:
# So when an instance variable is being accessed, and
# it has not been declared before, nor is it contained
# in dictionary 'data', an attribute exception needs to
# be raised.
raise AttributeError
def __setattr__(self, key, value):
if key in self.data:
# Assign valid dictionary items here:
self.data[key] = value
else:
# Assign anything else as an instance attribute:
super().__setattr__(key,value)
prova:
f = MyClass(**{'a': 'v1', 'b': 'v2'})
print("f.a = ", f.a)
print("f.b = ", f.b)
print("f.data = ", f.data)
f.a = 'c'
f.d = 'e'
print("f.a = ", f.a)
print("f.b = ", f.b)
print("f.data = ", f.data)
print("f.d = ", f.d)
print("f.x = ", f.x)
print("f.y = ", f.y)
# Should raise attributed Error
print("f.g = ", f.g)
uscita:
f.a = v1
f.b = v2
f.data = {'a': 'v1', 'b': 'v2'}
f.a = c
f.b = v2
f.data = {'a': 'c', 'b': 'v2'}
f.d = e
f.x = 1
f.y = 2
Traceback (most recent call last):
File "MyClass.py", line 49, in <module>
print("f.g = ", f.g)
File "MyClass.py", line 25, in __getattr__
raise AttributeError
AttributeError
Idealmente, non a tutti. ;-) – delnan
Probabilmente non vorrai davvero farlo in pratica. Se i tuoi dati appartengono a un ditt, usa un ditt; se i tuoi dati appartengono a un oggetto, usa un oggetto. Comunque, ['namedtuple'] (http://docs.python.org/3.3/library/collections.html#namedtuple-factory-function-for-tuples-with-named-fields), che funziona in modo gentile oggetto leggero, potrebbe fare quello che vuoi. –
Ricorda che '__getattr__' è usato solo per la ricerca degli attributi mancanti. – Kos