请问正确的成语是什么?
我想定义一个包含可以(可选)从字典(字典来自 JSON;它可能不完整)初始化的属性的对象。稍后我可能会通过 setter 修改属性。 实际上有超过 13 个属性,我希望能够使用默认的 getter 和 setter,但这似乎不适用于这种情况:
但我不想为所有 prop1...propn
编写显式描述符
另外,我想将默认赋值移出 __init__()
并移到访问器中……但是我需要明确的描述符。
什么是最优雅的解决方案? (除了将所有 setter 调用移出 __init__()
并移入方法/类方法 _make()
之外?)
[DELETED COMMENT 使用默认描述符的 badprop 代码是由于以前的 SO 用户的评论,他给人的印象是它给了你一个默认的 setter 。但它没有 - setter 未定义,它必然会抛出 AttributeError
。]
class DubiousPropertyExample(object):
def __init__(self,dct=None):
self.prop1 = 'some default'
self.prop2 = 'other default'
#self.badprop = 'This throws AttributeError: can\'t set attribute'
if dct is None: dct = dict() # or use defaultdict
for prop,val in dct.items():
self.__setattr__(prop,val)
# How do I do default property descriptors? this is wrong
#@property
#def badprop(self): pass
# Explicit descriptors for all properties - yukk
@property
def prop1(self): return self._prop1
@prop1.setter
def prop1(self,value): self._prop1 = value
@property
def prop2(self): return self._prop2
@prop2.setter
def prop2(self,value): self._prop2 = value
dub = DubiousPropertyExample({'prop2':'crashandburn'})
print dub.__dict__
# {'_prop2': 'crashandburn', '_prop1': 'some default'}
如果您在第 5 行 self.badprop = ...
未注释的情况下运行它,它将失败:
self.badprop = 'This throws AttributeError: can\'t set attribute'
AttributeError: 无法设置属性
[一如既往,我阅读了有关描述符、隐式描述符、从init 调用它们的 SO 帖子]
最佳答案
我认为您稍微误解了属性的工作原理。没有“默认 setter ”。它在设置 badprop
时抛出 AttributeError
不是因为它还不知道 badprop
是一个属性而不是一个普通属性(如果它是在这种情况下,它只会毫无错误地设置属性,因为这是现在正常的属性行为),但是因为您没有为 badprop
提供 setter,只有 getter。
看看这个:
>>> class Foo(object):
@property
def foo(self):
return self._foo
def __init__(self):
self._foo = 1
>>> f = Foo()
>>> f.foo = 2
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
f.foo = 2
AttributeError: can't set attribute
即使在__init__
之外,您也不能在构造实例后设置这样的属性。如果您只是使用@property
,那么您拥有的是一个只读属性(实际上是一个看起来像属性读取的方法调用)。
如果您在 getter 和 setter 中所做的只是将读/写访问重定向到具有相同名称但前缀为下划线的属性,那么到far为止,最简单的事情就是获取完全摆脱属性,只使用普通属性。 Python 不是 Java(即使在 Java 中,我也不相信私有(private)字段具有明显的公共(public) getter/setter 的优点)。外部世界可以直接访问的属性是您的“公共(public)”界面中一个完全合理的部分。如果你后来发现你需要在读/写属性时运行一些代码,你可以将它设为属性 then 而无需更改你的接口(interface)(这实际上是描述符最初的目的,不是这样我们就可以开始为每个属性编写 Java 风格的 getter/setter。
如果您实际上在属性中做一些事情而不是更改属性的名称,并且您确实希望您的属性是只读的,那么最好的办法可能是在__init__
直接设置带有下划线前缀的底层数据属性。然后您的类可以直接初始化而不会出现 AttributeErrors
,此后属性将在读取属性时执行它们的操作。
如果您实际上在属性中执行某些操作而不是更改属性的名称,并且您希望属性可读和可写,那么您需要实际指定获取/设置它们时发生的情况。如果每个属性都有独立的自定义行为,那么没有比为每个属性显式提供 getter 和 setter 更有效的方法了。
如果你在每一个 getter/setter 中运行完全相同(或非常相似)的代码(而且它不仅仅是在真实的属性名称上添加下划线),这就是你反对将它们全部写出来的原因(正确所以!),那么通过实现一些 __getattr__
、__getattribute__
和 __setattr__
可能会更好地为您服务。这些允许您每次将属性读取/写入重定向到相同代码(将属性名称作为参数),而不是为每个属性(获取/设置)重定向到两个函数。
关于python - 如何使用默认属性描述符并从 __init__() 成功分配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12065570/