3

リファレンスのデータモデルでは、ライターはユーザー定義のメソッドがどのように作成および操作されるかを説明するために多くの労力を費やしました:( http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchyおよびrollを参照)下)

ユーザー定義メソッドオブジェクトは、その属性がユーザー定義関数オブジェクト、バインドされていないユーザー定義メソッドオブジェクト、またはクラスメソッドである場合、クラスの属性を取得するときに(おそらく、そのクラスのインスタンスを介して)作成できます。物体。属性がユーザー定義のメソッドオブジェクトである場合、新しいメソッドオブジェクトは、それが取得されるクラスが元のメソッドオブジェクトに格納されているクラスと同じであるか、その派生クラスである場合にのみ作成されます。それ以外の場合は、元のメソッドオブジェクトがそのまま使用されます。

では、バインドされていないユーザー定義メソッドオブジェクトクラスメソッドオブジェクトの違いは何ですか?

4

1 に答える 1

6

「ユーザー」の観点から見ると、Pythonのクラスメソッドは、クラスのインスタンスを最初のパラメーターとして受け取る「通常の」メソッドとは異なり、クラスを最初のパラメーターとして受け取るメソッドです。これは、慣例によりと呼ばれselfます。

そのクラスのインスタンスからではなく、クラスから「通常の」メソッドを取得すると、「非バインドメソッド」が取得されます。つまり、関数のラッパーであるが、クラス自体も自動的に追加されないオブジェクトです。 、または呼び出されたときの最初のパラメータとしてのインスタンスもありません。したがって、「アンバウンドメソッド」を呼び出す場合は、そのクラスのインスタンスを最初のパラメータとして手動で渡す必要があります。

一方、クラスメソッドを手動で呼び出す場合、クラスは最初のパラメータとして入力されます。

>>> class A(object):
...   def b(self):
...      pass
...   @classmethod
...   def c(cls):
...      pass
... 
>>> A.b
<unbound method A.b>
>>> A.c
<bound method type.c of <class '__main__.A'>>
>>> A.c()
>>> A.b()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method b() must be called with A instance as first argument (got nothing instead)
>>> 

内部では、「新しいスタイルのクラス」を使用すると、多かれ少なかれ次のようになります。

クラス本体を定義する場合、メソッドは単なる通常の関数です-クラス本体が終了すると、Pythonはクラスのメタクラス(通常は組み込みtype)を呼び出し、名前、基本クラス、およびクラス本体ディクショナリをパラメーターとして渡します。 。この呼び出しにより、クラスが生成されます。Pythonでは、すべてがオブジェクトであるため、クラスであるオブジェクトです。

現在、Pythonには、属性アクセスをカスタマイズするための優れた方法がいくつかあります。いわゆる「記述子」です。記述子は、という名前のメソッドを定義するオブジェクトです__get__(または__set____del__ここではそれらを気にしません)。Pythonでクラスまたはオブジェクトの属性にアクセスすると、その属性によって参照されるオブジェクトが返されます。ただし、それがクラス属性であり、オブジェクトが記述子である場合を除きます。その場合、Pythonはオブジェクト自体を返す代わりに、 __get__そのオブジェクトのメソッドを呼び出し、代わりにその結果を返します。たとえば、組み込みは、とを適切にproperty実装する単なるクラスです。__set____get____del__

ここで、属性が取得されたときに何が起こるかというと、その本体の関数(またはデータモデルが示すようにクラスメソッドまたは非バインドメソッド)には__get__、記述子になるメソッドがあります。基本的に、各属性にアクセスして、関数本体で定義されている関数として指定されたオブジェクトを取得する記述子は、その関数の周囲に新しいオブジェクトを作成します。このオブジェクトを呼び出すと、最初のパラメーターが自動的に入力されます。と言うと、method

元。:

>>> class B(object):
...    def c(self):
...      pass
...    print c
... 
<function c at 0x1927398>
>>> print B.c
<unbound method B.c>
>>> b = B()
>>> b.c
<bound method B.c of <__main__.B object at 0x1930a10>

メソッドオブジェクトに変換せずに関数オブジェクトを取得する場合は__dict__、記述子をトリガーしないクラスの属性を使用して取得できます。

>>> B.__dict__["c"]
<function c at 0x1927398>
>>> B.__dict__["c"].__get__
<method-wrapper '__get__' of function object at 0x1927398>
>>> B.__dict__["c"].__get__(b, B)
<bound method B.c of <__main__.B object at 0x1930a10>>
>>> B.__dict__["c"].__get__(None, B)
<unbound method B.c>

「クラスメソッド」に関しては、これらは単なる異なるタイプのオブジェクトであり、組み込みで明示的に装飾されています。呼び出されclassmethodたときに返されるオブジェクトは、呼び出し時に最初のパラメーターとして入力__get__される元の関数のラッパーです。cls

于 2012-02-01T05:28:39.000 に答える