0

1)が機能しないのに2)と3)が機能する理由について、誰かが私にこの動作を説明できますか?

1)

class bm(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)


In [43]: ob1=bm('vin')

以下のコードは正常に機能しますが、再帰エラーが発生します

2)

class bm(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)


In [43]: ob1=bm('vin')

正常に動作します.ob.aにアクセスしてob.a=''を実行できます

これでも問題なく動作します

3)

class bm(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)

In [43]: ob1=bm('vin')

正常に動作します.ob.aにアクセスしてob.a=''を実行できます

4

2 に答える 2

5

a最初の例では、次のようなことができるプロパティを作成しています。

self.a               # Get the value
self.a = some_obj    # Set the value

しかし、プロパティ内では、 !を介してプロパティを再度a参照しています。これにより、再帰の問題が発生します。aself.a

次の例では、プロパティaは変数によってサポートされておりself._a、この再帰の問題を回避しています。

于 2012-07-03T18:33:03.923 に答える
3

ここでのポイントは、Python では、すべて (関数、メソッド、「プロパティ」、またはその他の記述子、クラス、さらにはモジュールを含む) がオブジェクトであり、「データ」と「関数またはメソッド」に個別の名前空間がないことです。IOW、Pythonでは、オブジェクトには属性、期間があります-「メンバーデータ」も「メンバー関数」もありません。基本クラスでさえ属​​性です(それ自体がオブジェクトであるため、属性もあります)。

属性ルックアップ ルールは次のとおりです (非常に単純化されています。スロットなどの特殊なケースについては言及しません)。

読むために:

  1. まず、親クラスでその名前の属性を探します。見つかった場合、およびこの属性が記述子プロトコルの「get」部分を実装している場合は、その属性の__get__メソッドを呼び出します。
  2. 次に、インスタンスのインスタンス属性を探します__dict__
  3. クラス(または親クラスの1つ)に__getattr__メソッドがある場合は、それを呼び出します
  4. 次に AttributeError 例外を発生させます

設定用:

  1. まず、親クラスでその名前の属性を探します。見つかった場合、およびこの属性が記述子プロトコルの「設定」部分を実装している場合は、その属性の__set__メソッドを呼び出します。
  2. 次に、属性をインスタンスの__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ある (クラス) 属性を持つクラス オブジェクトがあります。インスタンス化するとどうなるでしょうか。初期化子は引数で呼び出され、その引数にバインドしようとします。属性ルックアップ ルール (「書き込み」の場合 - 実際には「バインディング」と言うべきです) が開始され、クラス オブジェクトに、型のインスタンスとしてプロトコル記述子の一部を実装する属性があることがわかります。したがって、ルックアップ ルールは を呼び出し、これは に解決され、 として実装されます。新しい属性ルックアップ、ディスクリプタ プロトコルのバインディング部分を実装するクラス属性の検索、それの呼び出しなど...、バング、無限再帰。afget=Something.getfset=Something.setSomethingvalself.aSomethingaproperty__set__Something.a.__set__(theinstance, val)Something.a.fset(theinstance, val)self.a = vala

簡単に言うと、属性は属性であり、属性です;)

set3 番目の例では、メソッドは 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

于 2012-07-03T20:06:35.980 に答える