在 Python 中使用新式属性“无法设置属性”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4183432/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
'Can't set attribute' with new-style properties in Python
提问by Maxim Popravko
I'm trying to use new-style properties declaration:
我正在尝试使用新式属性声明:
class C(object):
def __init__(self):
self._x = 0
@property
def x(self):
print 'getting'
return self._x
@x.setter
def set_x(self, value):
print 'setting'
self._x = value
if __name__ == '__main__':
c = C()
print c.x
c.x = 10
print c.x
and see the following in console:
并在控制台中看到以下内容:
pydev debugger: starting
getting
0
File "\test.py", line 55, in <module>
c.x = 10
AttributeError: can't set attribute
what am I doing wrong? P.S.: Old-style declaration works fine.
我究竟做错了什么?PS:旧式声明工作正常。
采纳答案by Dave Webb
The documentation says the followingabout using decorator form of property:
文档说明了以下关于使用装饰器形式的内容property:
Be sure to give the additional functions the same name as the original property (x in this case.)
确保为附加函数提供与原始属性相同的名称(在本例中为 x。)
I have no idea why this is since if you use propertyas function to return an attribute the methods can be called whatever you like.
我不知道这是为什么,因为如果你使用propertyas 函数来返回一个属性,那么你可以随意调用这些方法。
So you need to change your code to the following:
因此,您需要将代码更改为以下内容:
@x.setter
def x(self, value):
'setting'
self._x = value
回答by Ignacio Vazquez-Abrams
The setter method has to have the same name as the getter. Don't worry, the decorator knows how to tell them apart.
setter 方法必须与 getter 具有相同的名称。别担心,装饰器知道如何区分它们。
@x.setter
def x(self, value):
...
回答by Kyle
When you call @x.setter, @x.getter, or @x.deleter, you're creating a new property object and giving it the name of the function you're decorating. So really, all that matters is that the last time you use a @x.*er decorator in the class definition, it has the name you actually want to use. But since this would leave your class namespace polluted with incomplete versions of the property you wish to use, it's best to use the same name to clean them up.
当您调用@x.setter、@x.getter 或@x.deleter 时,您正在创建一个新的属性对象并为其指定您正在装饰的函数的名称。所以,真正重要的是最后一次在类定义中使用 @x.*er 装饰器时,它具有您实际想要使用的名称。但是由于这会使您的类命名空间被您希望使用的属性的不完整版本污染,所以最好使用相同的名称来清理它们。
回答by Tcll
If you don't want the extra _xname slot, here's a complex little trick you can do:
(tested with Py34)
如果你不想要额外的_x名称槽,这里有一个复杂的小技巧你可以做:(
用 Py34 测试)
>>> class C(object):
__slots__ = ['x'] # create a member_descriptor
def __init__( self ):
self.x = 0
# or use this if you don't want to call x_setter:
#set_x( self, 0 )
>>> get_x = C.x.__get__ # member_descriptor getter
>>> set_x = C.x.__set__ # member_descriptor setter
>>> # define custom wrappers:
>>> def x_getter( self ):
print('getting')
return get_x( self )
>>> def x_setter( self, value ):
print('setting')
set_x( self, value )
>>> C.x = property( x_getter, x_setter ) # replace the member_descriptor
>>> c = C()
setting
>>> print(c.x)
getting
0
>>> c.x = 10
setting
>>>

