web-dev-qa-db-ja.com

Pythonプロパティはどのように機能しますか?

Pythonプロパティを正常に使用しましたが、どのように機能するかわかりません。クラス外のプロパティを逆参照すると、タイプproperty

@property
def hello(): return "Hello, world!"

hello  # <property object at 0x9870a8>

ただし、クラスにプロパティを配置すると、動作が大きく異なります。

class Foo(object):
   @property
   def hello(self): return "Hello, world!"

Foo().hello # 'Hello, world!'

バインドされていないFoo.hellopropertyオブジェクトのままなので、クラスのインスタンス化は魔法を行う必要がありますが、それはどのような魔法ですか?

70
Fred Foo

他の人が指摘したように、彼らは記述子と呼ばれる言語機能を使用します。

クラス_Foo.hello_を介してアクセスしたときに実際のプロパティオブジェクトが返される理由は、プロパティが__get__(self, instance, owner)特殊メソッドを実装する方法にあります。

  • 記述子がインスタンスでアクセスされる場合、そのインスタンスは適切な引数として渡され、ownerそのインスタンスのクラス
  • クラスを介してアクセスする場合、instanceはNoneであり、ownerのみが渡されます。 propertyオブジェクトはこれを認識し、selfを返します。

Descriptors howto の他に、言語ガイドの Implementing Descriptors および Invoking Descriptors に関するドキュメントも参照してください。

48
Tim Yates

@propertiesが適切に機能するためには、クラスはobjectのサブクラスである必要があります。クラスがobjectのサブクラスではない場合、セッターに初めてアクセスすると、セッターを介してアクセスするのではなく、実際には短い名前で新しい属性が作成されます。

以下はnotが正しく動作します。

class C(): # <-- Notice that object is missing

    def __init__(self):
        self._x = None

    @property
    def x(self):
        print 'getting value of x'
        return self._x

    @x.setter
    def x(self, x):
        print 'setting value of x'
        self._x = x

>>> c = C()
>>> c.x = 1
>>> print c.x, c._x
1 0

以下は正しく動作します

class C(object):

    def __init__(self):
        self._x = None

    @property
    def x(self):
        print 'getting value of x'
        return self._x

    @x.setter
    def x(self, x):
        print 'setting value of x'
        self._x = x

>>> c = C()
>>> c.x = 1
setting value of x
>>> print c.x, c._x
getting value of x
1 1
22
Timothy Vann

プロパティは descriptors であり、クラスインスタンスのメンバーの場合、ディスクリプタは特別に動作します。つまり、aA型のインスタンスであり、A.fooが記述子の場合、a.fooA.foo.__get__(a)と同等です。

11
Sven Marnach

propertyオブジェクトは、記述子プロトコルを実装するだけです。 http://docs.python.org/howto/descriptor.html

2
Achim