Python类@property:使用setter但是避开getter?
在python类中,@property是一个很好的装饰器,避免使用显式的setter和getter函数。 然而,它的开销是“古典”类function的2-5倍。 就我而言,在设置属性的情况下,这相当不错,与设置时需要完成的处理相比,开销不重要。
但是,在取得物业时我不需要处理。 它总是只是“返回self.property”。 有没有一个优雅的方式来使用setter,但不使用getter,而不需要使用不同的内部variables?
为了说明,下面的类具有属性“var”,它指的是内部variables“_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'
对于那些有兴趣的,在我的电脑上调用“var”平均需要204 ns,而调用“_var”平均需要44 ns。
在这种情况下不要使用property
。 一个property
对象是一个数据描述符,这意味着对instance.var
任何访问都将调用该描述符,Python将永远不会在实例本身上查找属性。
你有两个select:使用.__setattr__()
钩子或build立一个只能实现.__set__
的描述符。
使用.__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)
现在在读取 .var
时使用普通的属性查找,但是当赋值给.var
,会调用__setattr__
方法,让您截取value
并根据需要进行调整。
演示:
>>> mc = MyClass() >>> mc.var 'foo' >>> mc.var = 'bar' Setting var! >>> mc.var 'Set to bar'
一个setter描述符
setter描述符只会拦截variables赋值:
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
注意我们需要如何分配给实例.__dict__
属性来防止再次调用setter。
演示:
>>> 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文档: 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)
输出:
ok Traceback (most recent call last): File "Untitled.py", line 15, in <module> print c.var AttributeError: unreadable attribute