web-dev-qa-db-ja.com

Python class @property:setterを使用するが、getterを回避しますか?

pythonクラスでは、@ propertyは明示的なsetterおよびgetter関数の使用を回避するNiceデコレータです。ただし、「classical」クラスの2〜5倍のオーバーヘッドがかかります私の場合、プロパティを設定する場合、これはまったく問題ありません。設定時に行う必要がある処理に比べてオーバーヘッドはわずかです。

ただし、プロパティを取得するときに処理は必要ありません。常に「return self.property」です。別の内部変数を使用せずに、セッターを使用するがゲッターを使用しないエレガントな方法はありますか?

説明のためだけに、以下のクラスには、内部変数「_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'

興味のある人のために、私のPCでは、「_ var」を呼び出すと平均で44 nsかかりますが、「var」を呼び出すと平均で204 nsかかります。

47
Jonas Lindeløv

この場合、propertyを使用しないでください。 propertyオブジェクトはデータ記述子です。つまり、_instance.var_へのアクセスはすべてその記述子を呼び出し、Pythonはインスタンス自体の属性を検索しません。

次の2つのオプションがあります。 .__setattr__() フックを使用するか、_.__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)
_

reading_.var_の場合は通常の属性ルックアップが使用されますが、_.var_に割り当てる場合は、代わりに___setattr___メソッドが呼び出されます、valueをインターセプトし、必要に応じて調整できます。

デモ:

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

セッター記述子

セッター記述子は、変数の割り当てのみをインターセプトします。

_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___属性に割り当てて、セッターの再起動を防ぐ方法に注意してください。

デモ:

_>>> f = Foo()
>>> f.var = 'spam'
Setting var!
>>> f.var = 'ham'
Setting var!
>>> f.var
'ham'
>>> f.var = 'biggles'
Setting var!
>>> f.var
'biggles'
_
59
Martijn Pieters

property python docs: 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
28
WeizhongTu