【发布时间】:2017-08-30 16:12:26
【问题描述】:
我正在尝试构建一个基类用于所有其他对象的系统。每个基对象内部都有一个_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是不必要的。
标签: python class infinite-loop getattr setattr