Вы можете инициализировать словарь класса через конструктор:
def __init__(self,**data):
И называют его следующим образом:
f = MyClass(**{'a': 'v1', 'b': 'v2'})
Все экземпляра атрибутов осуществляется доступ (чтение) в __setattr__, должны быть объявлен, используя его метод родительского (супер), только один раз:
super().__setattr__('NewVarName1', InitialValue)
Или
super().__setattr__('data', dict())
После этого они могут быть доступны или переданы в обычном порядке:
self.data = data
И атрибуты экземпляра не доступны в __setattr__, могут быть объявлены в обычном порядке:
self.x = 1
Переопределенный метод __setattr__ должен теперь вызывать родительский метод внутри себя, для объявления новых переменных:
super().__setattr__(key,value)
Полный класс будет выглядеть следующим образом:
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)
Тест:
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)
Выход:
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
В идеале, не совсем. ;-) – delnan
Вы, вероятно, на самом деле не хотите делать это на практике. Если ваши данные принадлежат к dict, используйте dict; если ваши данные принадлежат объекту, используйте объект. В любом случае, ['namedtuple'] (http://docs.python.org/3.3/library/collections.html#namedtuple-factory-function-for-tuples-with-named-fields), который работает вроде как легкий объект, может делать то, что вы хотите. –
Помните, что '__getattr__' используется только для поиска отсутствующих атрибутов. – Kos