ここでのポイントは、Python では、すべて (関数、メソッド、「プロパティ」、またはその他の記述子、クラス、さらにはモジュールを含む) がオブジェクトであり、「データ」と「関数またはメソッド」に個別の名前空間がないことです。IOW、Pythonでは、オブジェクトには属性、期間があります-「メンバーデータ」も「メンバー関数」もありません。基本クラスでさえ属性です(それ自体がオブジェクトであるため、属性もあります)。
属性ルックアップ ルールは次のとおりです (非常に単純化されています。スロットなどの特殊なケースについては言及しません)。
読むために:
- まず、親クラスでその名前の属性を探します。見つかった場合、およびこの属性が記述子プロトコルの「get」部分を実装している場合は、その属性の
__get__
メソッドを呼び出します。
- 次に、インスタンスのインスタンス属性を探します
__dict__
- クラス(または親クラスの1つ)に
__getattr__
メソッドがある場合は、それを呼び出します
- 次に AttributeError 例外を発生させます
設定用:
- まず、親クラスでその名前の属性を探します。見つかった場合、およびこの属性が記述子プロトコルの「設定」部分を実装している場合は、その属性の
__set__
メソッドを呼び出します。
- 次に、属性をインスタンスの
__dict__
記述子プロトコルについて言及しましたが、説明しませんでした。このプロトコル (Java 出身の場合、プロトコルは一種の「暗黙の」インターフェースです。宣言する必要はなく、実装するだけです) は、オブジェクトに__get__
メソッドがあり、最終的には__set__
メソッドがある場合 (ここでも私は部分を言及しないことで過度に単純化し__del__
ます) AND がクラス属性である場合、クラス__get__
のインスタンスを検索すると、そのメソッドが呼び出され (インスタンスとクラスを引数として)、「読み取り」ルックアップで呼び出され、その__set__
メソッドが呼び出されます (インスタンスと値) 「書き込み」。
IOW、記述子プロトコルは、Python で計算された属性の基礎です。
タイプについてproperty
(はい、それはクラスであり、関数ではありません):非常に単純な方法で記述子プロトコルを実装します。以下は、プロパティ タイプが純粋な Python でどのように実装されるかの簡略化されたバージョンです (__del__
一部は考慮されていません)。
class property(object):
def __init__(self, fget, fset=None, doc=None):
self.fget = fget
self.fset = fset
self.doc = doc
def __get__(self, instance, cls=None):
if not instance:
return self
return self.fget(instance)
def __set__(self, instance, value):
if not self.fset:
raise AttributeError("attribute is read-only")
self.fset(instance, value)
質問に戻ります-クラスステートメントが与えられた場合:
class Something(object):
def __init__(self,val):
self.a=val
def get(self):
return self.a
def set(self,val):
self.a=val
a=property(get,set)
と を持つプロパティでSomething
ある (クラス) 属性を持つクラス オブジェクトがあります。インスタンス化するとどうなるでしょうか。初期化子は引数で呼び出され、その引数にバインドしようとします。属性ルックアップ ルール (「書き込み」の場合 - 実際には「バインディング」と言うべきです) が開始され、クラス オブジェクトに、型のインスタンスとしてプロトコル記述子の一部を実装する属性があることがわかります。したがって、ルックアップ ルールは を呼び出し、これは に解決され、 として実装されます。新しい属性ルックアップ、ディスクリプタ プロトコルのバインディング部分を実装するクラス属性の検索、それの呼び出しなど...、バング、無限再帰。a
fget=Something.get
fset=Something.set
Something
val
self.a
Something
a
property
__set__
Something.a.__set__(theinstance, val)
Something.a.fset(theinstance, val)
self.a = val
a
簡単に言うと、属性は属性であり、属性です;)
set
3 番目の例では、メソッドは setself._a
ではなくを試行することに注意してくださいself.a
。クラスには という名前の記述子がないため_a
、これはその名前でインスタンス属性を作成するだけなので、ここでは再帰はありません。
記述子プロトコルの詳細については、http://docs.python.org/reference/datamodel.html#implementing-descriptors
- http://wiki.python.org/moin/ComputedAttributesUsingPropertyObjectsを参照してください。
function
また、Python の「メソッド」が実際に何であるか (ヒント:記述子プロトコルを実装する型) と、「self」引数が必要な理由を理解したい場合は、これも読むことができます: - http://wiki.python.org/ moin/FromFunctionToMethod