組み込み関数がどのようにproperty
動作するかを理解したいと思います。混乱しているのは、組み込み関数はproperty
デコレータとしても使用できるのに、組み込み関数として使用する場合にのみ引数を受け取り、デコレータとして使用する場合には引数を受け取らないことです。
この例は、ドキュメンテーション:
class C:
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
property
の引数は、、getx
およびドキュメント文字列です。setx
delx
以下のコードではproperty
デコレータとして使用されています。そのオブジェクトは関数ですx
が、上記のコードでは引数にオブジェクト関数を入れる場所がありません。
class C:
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
この場合、x.setter
およびデコレータはどのように作成されますか?x.deleter
ベストアンサー1
このproperty()
関数は特別な記述子オブジェクト:
>>> property()
<property object at 0x10ff07940>
追加のメソッドを持つのはこのオブジェクトです:
>>> property().getter
<built-in method getter of property object at 0x10ff07998>
>>> property().setter
<built-in method setter of property object at 0x10ff07940>
>>> property().deleter
<built-in method deleter of property object at 0x10ff07998>
これらもデコレータとして機能します。新しいプロパティ オブジェクトを返します。
>>> property().getter(None)
<property object at 0x10ff079f0>
これは古いオブジェクトのコピーですが、関数の 1 つが置き換えられています。
覚えておいてください、@decorator
構文は単なる構文糖です。構文:
@property
def foo(self): return self._foo
実際には同じ意味です
def foo(self): return self._foo
foo = property(foo)
したがって、foo
関数は に置き換えられますproperty(foo)
。これは、上で説明したように、特別なオブジェクトです。次に を使用すると@foo.setter()
、上で示したメソッドが呼び出されproperty().setter
、プロパティの新しいコピーが返されますが、今回はセッター関数が装飾されたメソッドに置き換えられます。
次のシーケンスでも、これらのデコレータ メソッドを使用して完全なプロパティを作成します。
まず、いくつかの関数を作成します。
>>> def getter(self): print('Get!')
...
>>> def setter(self, value): print('Set to {!r}!'.format(value))
...
>>> def deleter(self): print('Delete!')
...
次に、property
ゲッターのみを持つオブジェクトを作成します。
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True
次に、.setter()
メソッドを使用してセッターを追加します。
>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True
最後に、メソッドを使用して削除子を追加します.deleter()
。
>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True
最後に、このproperty
オブジェクトは記述子オブジェクト、それは.__get__()
、.__set__()
そして.__delete__()
インスタンス属性の取得、設定、削除にフックするメソッド:
>>> class Foo: pass
...
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!
記述子Howtoには、純粋なPythonサンプル実装タイプproperty()
:
class Property: "Emulate PyProperty_Type() in Objects/descrobject.c" def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel if doc is None and fget is not None: doc = fget.__doc__ self.__doc__ = doc def __get__(self, obj, objtype=None): if obj is None: return self if self.fget is None: raise AttributeError("unreadable attribute") return self.fget(obj) def __set__(self, obj, value): if self.fset is None: raise AttributeError("can't set attribute") self.fset(obj, value) def __delete__(self, obj): if self.fdel is None: raise AttributeError("can't delete attribute") self.fdel(obj) def getter(self, fget): return type(self)(fget, self.fset, self.fdel, self.__doc__) def setter(self, fset): return type(self)(self.fget, fset, self.fdel, self.__doc__) def deleter(self, fdel): return type(self)(self.fget, self.fset, fdel, self.__doc__)