Я пытаюсь построить систему, в которой базовый класс используется для каждого другого объекта. Каждый базовый объект имеет внутренний словарь _fields
, в котором реализации базового класса могут хранить свою информацию.
Реализация базового класса довольно проста:
class A(object):
def __init__(self, fields=dict()):
self._fields = fields
Реализация класса может установить поле в вызове __init__
в его super()
.
Я хотел бы добавить, что поля доступны как свойства без добавления декоратора @property
к целому набору функций. Для этой цели я переопределил __getattr__
в базовом классе следующим образом:
class A(object):
def __init__(self, fields=dict()):
self._fields = fields
def __getattr__(self, name):
if hasattr(self, name):
return object.__getattribute__(self, name)
elif name in self._fields:
return self._fields.get(name)
else:
raise AttributeError
Теперь реализация для этого класса может работать так:
class A_impl(A):
def __init__(self):
super(A_impl, self).__init__(
fields=dict(
val_1="foo",
val_2="",
val_3="bar",
)
)
Благодаря чему создание реализации этого класса дает вам следующие возможности:
test = A_imp()
print test.val_1
print test.val_2
print test.val_3
Что возвращает
foo
bar
Я даже могу переопределить это с помощью декораторов @property
, изменив класс следующим образом:
class A_impl(A):
def __init__(self):
super(A_impl, self).__init__(
fields=dict(
val_1="foo",
val_2="",
val_3="bar",
)
)
@property
def val_1(self):
return self._fields.get('val_1') + "_getter"
Что позволяет мне манипулировать данными для возврата. Единственная проблема заключается в том, что если я хочу иметь возможность установить одну из этих переменных поля, я должен реализовать функции установки дескриптора, что также требует от меня создания дескриптора свойства, который создает много дублирующей работы ( т.е. я должен определить дескрипторы для ВСЕХ моих полей, чего я хочу избежать здесь.
Я реализовал функцию __setattr__
для базового класса, чтобы решить проблему, из-за которой, если я вручную реализую функцию установки дескриптора, ее следует выбирать вместо значения по умолчанию, которое равно self._field[name] = value
. Базовый класс теперь выглядит так (аналогично __getattr__
):
class A(object):
def __init__(self, fields=dict()):
self._fields = fields
def __getattr__(self, name):
if hasattr(self, name):
return object.__getattribute__(self, name)
elif name in self._fields:
return self._fields.get(name)
else:
raise AttributeError
def __setattr__(self, name, value):
if hasattr(self, name):
object.__setattr__(self, name, value)
elif name in self._fields:
self._fields[name] = value
else:
raise AttributeError
Теперь, если я снова запущу тот же тест кода:
test = A_imp()
print test.val_1
print test.val_2
print test.val_3
Он мгновенно застревает в бесконечном цикле, он начинается с __setattr__
, но сразу же переходит в __getattr__
и продолжает цикл.
Я читал много вопросов о stackoverflow для этого и не мог понять, поэтому я создаю этот тестовый пример, чтобы четко понять это. Надеюсь, кто-то сможет прояснить это для меня и помочь мне решить проблему.
hasattr
не нужно. - person o11c   schedule 30.08.2017