4

いくつかのコードから始めましょう:

def func(*x):
    print('func:', x)


class ABC:
    def __init__(self, f):
        self.f1 = f

    def f2(*x):
        print('f2:', x)

次に、いくつかのテストを行います。

>>> a = ABC(func)
>>> a.f1(10)
func: (10,)
>>> a.f2(10)
f2: (<__main__.ABC object at 0xb75381cc>, 10)
>>> a.f3 = func
>>> a.f3(10)
func: (10,)
>>> a.f1
<function func at 0xb74911ec>
>>> a.f2
<bound method ABC.f2 of <__main__.ABC object at 0xb75381cc>>
>>> a.f3
<function func at 0xb74911ec>

funcこれは通常の関数でf1あり、クラスのメソッドにしていることに注意してください。

すべての関数がクラスメソッドとして呼び出されている場合でもf2、最初の引数としてクラスインスタンスを取得していることがわかりますが、そうではf1ありません。f3また、クラスのメソッドとして正規関数を呼び出す場合、Pythonはそれからバインドされたメソッドを作成しないこともわかります。

では、クラスのメソッドとして呼び出している場合でも、クラスインスタンスが渡されるのはなぜf1ですか?f3また、Pythonは、インスタンスを渡さないように、外部関数をメソッドとして呼び出していることをどのように認識しますか。

- 編集 -

さて、基本的に私が間違っているのは、クラスオブジェクト自体ではなく、インスタンスに関数をアタッチしているということです。したがって、これらの関数は単にインスタンス属性になります。これは次のように確認できます。

>>> ABC.__dict__
... contents...
>>> a.__dict__
{'f1': <function func at 0xb74911ec>, 'f3': <function func at 0xb74911ec>}

また、このdictは以下に割り当てることができないことに注意してください。

>>> ABC.__dict__['f4'] = func
TypeError: 'dict_proxy' object does not support item assignment
4

2 に答える 2

8

オブジェクトを調べて、自分の質問に部分的に答えました。Pythonでは、オブジェクトは名前空間のように動作するため、最初の属性は関数を指し、2番目の属性はメソッドを指します。

これは、メソッドを動的に追加する方法です。

from types import MethodType

def func(*x):
    print('func:', x)


class ABC:
    def __init__(self, f):
        self.f1 = MethodType(f, self, self.__class__)

    def f2(*x):
        print('f2:', x)

if __name__ == '__main__':
    a = ABC(func)
    print a.f1(10)
    print a.f2(10)
    a.f3 = MethodType(func, a, ABC)
    print a.f3(10)

メソッドを基本クラスではなくインスタンスにバインドすることに注意してください。ABCクラスにモンキーパッチを適用するには:

>>> ABC.f4 = MethodType(func, None, ABC)
>>> a.f4(1)
('func:', (<__main__.ABC instance at 0x02AA8AD0>, 1))

モンキーパッチは、他の動的言語(特に言語が若い頃のRuby)で人気があったにもかかわらず、通常Pythonサークルでは嫌われています。

この強力で危険なテクニックに頼るなら、私のアドバイスは次のとおりです。

  • 既存のクラスメソッドをオーバーライドすることは決してありません。しないでください。
于 2012-11-23T07:09:29.547 に答える
3

これは、クラスメソッドf1f3はなく、__main__:で定義されたグローバル関数への単なる参照であるためです。

In [5]: a.f1
Out[5]: <function __main__.func>

In [8]: a.f3
Out[8]: <function __main__.func>

In [9]: a.f2
Out[9]: <bound method ABC.f2 of <__main__.ABC instance at 0x8ac04ac>>

次のようなことを実行して、グローバル関数をクラスメソッドにすることができます。

In [16]: class ABC:
    def __init__(self,f):
        ABC.f1=f
    def f2(*x):    
        print('f2',x)
   ....:         

In [17]: a=ABC(func)

In [18]: a.f1(10)
('func:', (<__main__.ABC instance at 0x8abb7ec>, 10))
于 2012-11-23T07:03:25.780 に答える