Python 类@property:使用 setter 但避开 getter?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17576009/
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
Python class @property: use setter but evade getter?
提问by Jonas Lindel?v
In python classes, the @property is a nice decorator that avoids using explicit setter and getter functions. However, it comes at a cost of an overhead 2-5 times that of a "classical" class function. In my case, this is quite OK in the case of setting a property, where the overhead is insignificant compared to the processing that needs to be done when setting.
在 python 类中,@property 是一个很好的装饰器,它避免使用显式的 setter 和 getter 函数。但是,它的开销是“经典”类函数的 2-5 倍。在我的情况下,这在设置属性的情况下非常好,与设置时需要完成的处理相比,开销微不足道。
However, I need no processing when getting the property. It is always just "return self.property". Is there an elegant way to use the setter but not using the getter, without needing to use a different internal variable?
但是,我在获得财产时不需要处理。它始终只是“返回 self.property”。有没有一种优雅的方法来使用 setter 但不使用 getter,而不需要使用不同的内部变量?
Just to illustrate, the class below has the property "var" which refers to the internal variable "_var". It takes longer to call "var" than "_var" but it would be nice if developers and users alike could just use "var" without having to keep track of "_var" too.
只是为了说明,下面的类具有属性“var”,它指的是内部变量“_var”。调用“var”比调用“_var”需要更长的时间,但如果开发人员和用户都可以只使用“var”而不必跟踪“_var”,那就太好了。
class MyClass(object):
def __init__(self):
self._var = None
# the property "var". First the getter, then the setter
@property
def var(self):
return self._var
@var.setter
def var(self, newValue):
self._var = newValue
#... and a lot of other stuff here
# Use "var" a lot! How to avoid the overhead of the getter and not to call self._var!
def useAttribute(self):
for i in xrange(100000):
self.var == 'something'
For those interested, on my pc calling "var" takes 204 ns on average while calling "_var" takes 44 ns on average.
对于那些感兴趣的人,在我的电脑上调用“var”平均需要 204 ns,而调用“_var”平均需要 44 ns。
采纳答案by Martijn Pieters
Don't use a property
in this case. A property
object is a data descriptor, which means that any access to instance.var
will invoke that descriptor and Python will never look for an attribute on the instance itself.
property
在这种情况下不要使用 a 。一个property
对象是一个数据描述符,这意味着任何访问instance.var
将调用该描述符和Python将永远不会寻找在实例本身的属性。
You have two options: use the .__setattr__()
hook or build a descriptor that only implements .__set__
.
您有两个选择:使用.__setattr__()
钩子或构建仅实现.__set__
.
Using the .__setattr__()
hook
使用.__setattr__()
钩子
class MyClass(object):
var = 'foo'
def __setattr__(self, name, value):
if name == 'var':
print "Setting var!"
# do something with `value` here, like you would in a
# setter.
value = 'Set to ' + value
super(MyClass, self).__setattr__(name, value)
Now normal attribute lookups are used when reading.var
but when assigning to .var
the __setattr__
method is invoked instead, letting you intercept value
and adjust it as needed.
现在,当正常的属性查询用来阅读.var
,但分配给当.var
该__setattr__
方法被调用来代替,让你拦截value
,并根据需要进行调整。
Demo:
演示:
>>> mc = MyClass()
>>> mc.var
'foo'
>>> mc.var = 'bar'
Setting var!
>>> mc.var
'Set to bar'
A setter descriptor
一个 setter 描述符
A setter descriptor would only intercept variable assignment:
setter 描述符只会拦截变量赋值:
class SetterProperty(object):
def __init__(self, func, doc=None):
self.func = func
self.__doc__ = doc if doc is not None else func.__doc__
def __set__(self, obj, value):
return self.func(obj, value)
class Foo(object):
@SetterProperty
def var(self, value):
print 'Setting var!'
self.__dict__['var'] = value
Note how we need to assign to the instance .__dict__
attribute to prevent invoking the setter again.
请注意我们需要如何分配实例.__dict__
属性以防止再次调用 setter。
Demo:
演示:
>>> f = Foo()
>>> f.var = 'spam'
Setting var!
>>> f.var = 'ham'
Setting var!
>>> f.var
'ham'
>>> f.var = 'biggles'
Setting var!
>>> f.var
'biggles'
回答by WeizhongTu
property
python docs: https://docs.python.org/2/howto/descriptor.html#properties
property
python 文档:https: //docs.python.org/2/howto/descriptor.html#properties
class MyClass(object):
def __init__(self):
self._var = None
# only setter
def var(self, newValue):
self._var = newValue
var = property(None, var)
c = MyClass()
c.var = 3
print ('ok')
print (c.var)
output:
输出:
ok
Traceback (most recent call last):
File "Untitled.py", line 15, in <module>
print c.var
AttributeError: unreadable attribute
回答by Nuno André
The accepted answer's setter descriptor would be probably more convenient if it set the property by itself:
如果它自己设置属性,则接受的答案的 setter 描述符可能会更方便:
A setter descriptor (alt.)
一个 setter 描述符 (alt.)
class setter:
def __init__(self, func, doc=None):
self.func = func
self.__doc__ = doc or func.__doc__
def __set__(self, obj, value):
obj.__dict__[self.func.__name__] = self.func(obj, value)
class Foo:
@setter
def var(self, value):
print('Setting var!')
# validations and/or operations on received value
if not isinstance(value, str):
raise ValueError('`var` must be a string')
value = value.capitalize()
# returns property value
return value
Demo:
演示:
>>> f = Foo()
>>> f.var = 'spam'
Setting var!
>>> f.var = 'ham'
Setting var!
>>> f.var
'Ham'
>>> f.var = 'biggles'
Setting var!
>>> f.var
'Biggles'
>>> f.var = 3
ValueError: `var` must be a string
回答by Lore
The @WeizhongTu answer
@WeizhongTu 的回答
class MyClass(object):
def __init__(self):
self._var = None
# only setter
def var(self, newValue):
self._var = newValue
var = property(None, var)
c = MyClass()
c.var = 3
print ('ok')
print (c.var)
Is fine, except from the fact that is making the variable ungettable...
很好,除了使变量无法获取的事实......
A similar solution but preserving getteris with
一个类似的解决方案,但保留吸气剂是
var = property(lambda self: self._var, var)
instead of
代替
var = property(None, var)