[解決済み] Pythonの@propertyデコレーターはどのように機能するのでしょうか?
質問
ビルトイン関数の
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
とdocの文字列を指定します。
以下のコードでは
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
この場合に作成されるデコレーターは?
解決方法は?
その
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
このメソッドはプロパティの新しいコピーを返しますが、今回はセッター関数がデコレートされたメソッドに置き換えられています。
次のシーケンスも、これらのデコレータ・メソッドを使用して、完全なプロパティを作成します。
まず、いくつかの関数と
property
オブジェクトにゲッターを追加しただけのものです。
>>> def getter(self): print('Get!')
...
>>> def setter(self, value): print('Set to {!r}!'.format(value))
...
>>> def deleter(self): print('Delete!')
...
>>> 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!
Descriptor 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__)
関連
-
PicgoのイメージベッドツールをPythonで実装する
-
[解決済み】SyntaxError: デフォルト以外の引数がデフォルトの引数に続く
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] Pythonで2つのリストを連結する方法は?
-
[解決済み] ファイルのコピー方法について教えてください。
-
[解決済み] Pythonでファイルやフォルダを削除する方法は?
-
[解決済み] pipでPythonの全パッケージをアップグレードする方法
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】Pythonに三項条件演算子はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ピロウズ画像色処理の具体的な活用方法
-
Pythonコンテナのための組み込み汎用関数操作
-
python call matlab メソッドの詳細
-
Python jiabaライブラリの使用方法について説明
-
Pythonを使って簡単なzipファイルの解凍パスワードを手作業で解く
-
Pythonの@decoratorsについてまとめてみました。
-
[解決済み】Python regex AttributeError: 'NoneType' オブジェクトに 'group' 属性がない。
-
[解決済み】 AttributeError: モジュール 'matplotlib' には属性 'plot' がない。
-
[解決済み】「SyntaxError.Syntax」は何ですか?Missing parentheses in call to 'print'」はPythonでどういう意味ですか?
-
[解決済み】Python elifの構文が無効です【終了しました