smc*_*mci 3 python default properties propertydescriptor
请问这个正确的习惯用法是什么?
我想定义一个包含属性的对象,这些属性可以(可选)从dict初始化(dict来自JSON;它可能不完整).稍后我可以通过setter修改属性.实际上有13个以上的属性,我希望能够使用默认的getter和setter,但这似乎不适用于这种情况:
但是我不想为所有人编写显式描述符.prop1... propn
另外,我想将默认赋值移出__init__()访问者...但是我需要expicit描述符.
什么是最优雅的解决方案?(除了将所有的setter调用移出__init__()一个方法/ classmethod _make()?)
[删除评论]使用默认描述符的badprop代码是由之前的SO用户发表的评论,他给人的印象是它给你一个默认的设置器.但事实并非如此 - 设定者未定义且必然会抛出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'}
Run Code Online (Sandbox Code Playgroud)
如果您使用第5行self.badprop = ...取消注释运行它,它将失败:
self.badprop = 'This throws AttributeError: can\'t set attribute'
Run Code Online (Sandbox Code Playgroud)
AttributeError:无法设置属性
[与以往一样,我阅读描述符,隐式描述符的SO帖子,从init调用它们]
我认为你对属性如何运作有点误解.没有"默认设置器".它抛出一个AttributeErroron设置badprop不是因为它还不知道这badprop是一个属性而不是一个普通的属性(如果是这样的话,它只会设置没有错误的属性,因为现在这是正常的属性),但是因为你没有没有为badprop吸气剂提供装置.
看看这个:
>>> 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
Run Code Online (Sandbox Code Playgroud)
__init__在构造实例之后,您甚至无法在外部设置此类属性.如果您只是使用@property,那么您拥有的是只读属性(实际上是一个看起来像属性读取的方法调用).
如果您在getter和setter中所做的一切都是重定向对同名属性的读/写访问,但前缀是下划线,那么到目前为止最简单的方法是完全删除属性并使用普通属性.Python不是Java(甚至在Java中我也不相信具有明显公共getter/setter的私有字段的优点).外部世界可直接访问的属性是"公共"界面中非常合理的一部分.如果你以后发现每当读取/写入一个属性时你需要运行一些代码,你就可以把它变成一个属性然后不用改变你的界面(这实际上就是那些描述符最初的用途,而不是让我们开始编写Java风格的getter)每个属性的/ setter).
如果您实际上在属性中执行某些操作而不是更改属性的名称,并且您确实希望您的属性是只读的,那么最好的办法是将初始化__init__视为直接使用下划线设置基础数据属性前缀.然后你的类可以直接初始化AttributeErrors,然后属性将在读取属性时执行.
如果你实际做比改变属性的名称等属性的东西,你想你的属性是可读写的,那么你就需要实际指定在获取/设置他们发生了什么.如果每个属性都有独立的自定义行为,那么没有比为每个属性显式提供getter和setter更有效的方法.
如果你在每个getter/setter中运行完全相同(或非常相似)的代码(并且它不只是在真实属性名称中添加下划线),那就是你反对将它们全部写出来的原因(这是正确的!) ,那么你可能会更好地实现一些服务__getattr__,__getattribute__和__setattr__.这些允许您每次将属性读/写重定向到相同的代码(以属性的名称作为参数),而不是每个属性的两个函数(获取/设置).
| 归档时间: |
|
| 查看次数: |
4068 次 |
| 最近记录: |