Python 类@property:使用 setter 但避开 getter? [英] Python class @property: use setter but evade getter?

查看:29
本文介绍了Python 类@property:使用 setter 但避开 getter?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 python 类中,@property 是一个很好的装饰器,它避免使用显式的 setter 和 getter 函数.但是,它的开销是经典"类函数的 2-5 倍.在我的情况下,这在设置属性的情况下非常好,与设置时需要完成的处理相比,开销微不足道.

但是,我在获得财产时不需要处理.它始终只是返回 self.property".有没有一种优雅的方式来使用 setter 但不使用 getter,而不需要使用不同的内部变量?

只是为了说明,下面的类具有属性var",它指的是内部变量_var".调用var"比调用_var"需要更长的时间,但如果开发人员和用户都可以使用var"而不必跟踪_var",那就太好了.

class MyClass(object):def __init__(self):self._var = 无# 属性var".首先是 getter,然后是 setter@财产定义变量(自我):返回 self._var@var.setterdef var(self, newValue):self._var = newValue#...这里还有很多其他的东西# 经常使用var"!如何避免getter的开销而不是调用self._var!def useAttribute(self):对于 xrange(100000) 中的 i:self.var == '东西'

对于那些感兴趣的人,在我的电脑上调用var"平均需要 204 ns,而调用_var"平均需要 44 ns.

解决方案

在这种情况下不要使用 property.property 对象是一个数据描述符,这意味着对 instance.var 的任何访问都将调用该描述符,Python 永远不会在实例本身上查找属性.>

您有两个选择:使用 .__setattr__() 钩子或构建一个仅实现 .__set__ 的描述符.

使用 .__setattr__() 钩子

class MyClass(object):var = 'foo'def __setattr__(self, name, value):如果名称 == 'var':打印设置变量!"# 在这里用 `value` 做一些事情,就像你在#二传手.值 = '设置为 ' + 值super(MyClass, self).__setattr__(name, value)

现在在读取 .var 时使用正常的属性查找,但在分配给 .var 时使用 __setattr__ 方法而是调用,让您拦截 value 并根据需要进行调整.

演示:

<预><代码>>>>mc = MyClass()>>>麦克瓦尔'富'>>>mc.var = '酒吧'设置变量!>>>麦克瓦尔'设置为酒吧'

setter 描述符

setter 描述符只会拦截变量赋值:

class SetterProperty(object):def __init__(self, func, doc=None):self.func = funcself.__doc__ = doc 如果 doc 不是 None else func.__doc__def __set__(self, obj, value):返回 self.func(obj, value)类 Foo(对象):@SetterPropertydef var(self, value):打印设置变量!"self.__dict__['var'] = value

注意我们需要如何分配给实例 .__dict__ 属性以防止再次调用 setter.

演示:

<预><代码>>>>f = Foo()>>>f.var = '垃圾邮件'设置变量!>>>f.var = '火腿'设置变量!>>>变量'火腿'>>>f.var = 'biggles'设置变量!>>>变量'大事'

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.

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?

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.

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.

解决方案

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.

You have two options: use the .__setattr__() hook or build a descriptor that only implements .__set__.

Using the .__setattr__() hook

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.

Demo:

>>> mc = MyClass()
>>> mc.var
'foo'
>>> mc.var = 'bar'
Setting var!
>>> mc.var
'Set to bar'

A setter descriptor

A setter descriptor would only intercept variable assignment:

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.

Demo:

>>> f = Foo()
>>> f.var = 'spam'
Setting var!
>>> f.var = 'ham'
Setting var!
>>> f.var
'ham'
>>> f.var = 'biggles'
Setting var!
>>> f.var
'biggles'

这篇关于Python 类@property:使用 setter 但避开 getter?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆