[英]Python class @property: use setter but evade getter?
In python classes, the @property is a nice decorator that avoids using explicit setter and getter functions.在 python 类中,@property 是一个很好的装饰器,它避免使用显式的 setter 和 getter 函数。 However, it comes at a cost of an overhead 2-5 times that of a "classical" class function.但是,它的开销是“经典”类函数的 2-5 倍。 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.在我的情况下,这在设置属性的情况下非常好,与设置时需要完成的处理相比,开销微不足道。
However, I need no processing when getting the property.但是,我在获得财产时不需要处理。 It is always just "return self.property".它始终只是“返回 self.property”。 Is there an elegant way to use the setter but not using the getter, without needing to use a different internal variable?有没有一种优雅的方法来使用 setter 但不使用 getter,而不需要使用不同的内部变量?
Just to illustrate, the class below has the property "var" which refers to the internal variable "_var".只是为了说明,下面的类具有属性“var”,它指的是内部变量“_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”,那就太好了。
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。
Don't use a property
in this case.在这种情况下不要使用property
。 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
对象是一个数据描述符,这意味着对instance.var
任何访问都将调用该描述符并且 Python 永远不会在实例本身上查找属性。
You have two options: use the .__setattr__()
hook or build a descriptor that only implements .__set__
.您有两个选择:使用.__setattr__()
钩子或构建仅实现.__set__
的描述符。
.__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 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'
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
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 getter is with一个类似的解决方案,但保留吸气剂是
var = property(lambda self: self._var, var)
instead of代替
var = property(None, var)
The accepted answer's setter descriptor would be probably more convenient if it set the property by itself:如果它自己设置属性,则接受的答案的 setter 描述符可能会更方便:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.