8

あるクラスから別のクラスにメソッドを「盗む」またはコピーするにはどうすればよいですか?

コード例:

class A(object):
  def foo(self):
    print "blah"


class B(object):
  foo = A.foo

B().foo()

期待される出力:

"blah"

その代わり:

TypeError:バインドされていないメソッドfoo()は、最初の引数としてインスタンスを使用して呼び出す必要があります(代わりに何も取得しません)

4

4 に答える 4

7

使用__func__

>>> A.foo
<unbound method A.foo>
>>> A.foo.__func__
<function foo at 0x00BC5F70>
>>> class B(object):
...   foo = A.foo.__func__
...
>>> B().foo()
"blah"

ドキュメントの引用:

インスタンスメソッドオブジェクトは、クラス、クラスインスタンス、および任意の呼び出し可能オブジェクト(通常はユーザー定義関数)を組み合わせたものです。

特別な読み取り専用属性:__ self__はクラスインスタンスオブジェクト、__func__は関数オブジェクトです。__doc__はメソッドのドキュメントです(__func __.__ doc__と同じ)。__name__はメソッド名です(__func __.__ name__と同じ)。__module__は、メソッドが定義されたモジュールの名前です。使用できない場合は、Noneです。

于 2012-11-24T03:03:21.040 に答える
2

ここでクラス継承を使用できます。継承を使用すると、別のオブジェクトに基づいてオブジェクトを作成し、そのすべての機能と属性を継承できます。

この場合、次のようになります。

class A(object):
  def foo(self):
    print "blah"


class B(A):
  # You can add new methods or attributes here,
  #  or even overwrite those inherited from A if you
  #  really want to, though you have to be careful with that.
  pass

その宣言の後、

>>> B().foo()
"blah"

これが機能する理由は次のとおりです。

  • クラスAを作成し、そのためのメソッドを作成しましたfoo
  • あなたはからB 継承するクラスを作成しました。Aつまり、A「それを生んだ」とき、持っBているすべてのもので生まれましたA
    • 私たちの場合、は、他に何もしなかったので、Bの正確なコピーです。Aただし、変更を加えたり、メソッドを追加したりすることはできます。

例:

class A(object):
    def foo(self):
        print "blah"

class B(A):
   def newfoo(self):
       print "class A can't do this!"

どちらを使用すると、次のように表示されます。

>>> A().foo()
blah
>>> B().foo()
blah
>>> A().newfoo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'newfoo'
>>> B().newfoo()
class A can't do this!

特に、上記のコードが機能しなかった理由は、設定しようとしたときにB.foo

class B(object):
    foo = A.foo

それ以外の

class B(object):
    foo = A().foo

A.fooなしで書いたとき、あなたは()から直接メソッドを求めていましたが、これはPythonでは機能しません。行う場合は、オブジェクトをインスタンス化し、そのメソッドのコピーを取得して、それを割り当てることです。 A foo = A().fooAfoo

于 2012-11-24T02:59:08.493 に答える
2

ここでの問題は、それがあなたが盗もうとしているバインドされたメソッドであるということですが、あなたの例はインスタンス状態(self)を使用する関数を含んでいません。したがって、2つの即時オプションがあります。

  1. A.foo静的メソッド(@staticmethodデコレータ)の定義を作成します
  2. 関数を装飾またはラップして、未使用の引数を渡します。たとえば、を使用しfunctoolsます。

例えば。

import functools
stolen = functools.partial(A.foo, None)

これが機能するのは、メソッドがインスタンス状態を使用せず、サブクラスを作成する必要がないためです。

もう少し装飾するために、バインドされたインスタンスメソッド(のようなA.foo)は、バインドされたインスタンスの引数(self、selfはのインスタンス)を期待しますA。通常の使用法では、この最初の引数は自動的に渡されます。

a = A()

今:

a.foo()
A.foo(a)

...両方とも同等です。最初のケースでは、構文は字句の観点から推測します(instance.bound_method()に解決されます)。これが、のインスタンスを想定しているため、呼び出しによってエラーが発生する理由です。InstanceClass.bound_method(instance)instanceselfA.foo()A

上記の解決策は、インスタンスがとにかく使用されることはないため、関数をインスタンスとして渡す関数にワープするNoneことです(状態ベースのロジックはありません)。staticmethodを使用する場合は、最初の暗黙の期待されるバインドされたインスタンス引数を削除しますself

于 2012-11-24T03:07:56.970 に答える
0

バインドされていないメソッドが削除されているため、Python 3で機能します(Guido van Rossumの記事を参照)。

ただし、バインドされていないメソッドは、最初に渡された引数がメソッドを定義するクラスのインスタンスであることを暗黙的にチェックするための関数ラッパーであることに注意してください。これは、通常は違反してはならないメソッドの前提条件です。エラーメッセージは、継承である正しい解決策を示しました。

class B(A):
    pass

一般に、非基本クラスからメソッドを盗むべきではありませんsuper()。非基本クラスの呼び出し(の略)を壊してしまうからsuper(__class__, self)です。確かに、このプログラム:

class A(object):

    def foo(self):
        print "blah"
        super().__init__()


class B(object):
    foo = A.foo.__func__


B().foo()

レイズ:

TypeError: super(type, obj): obj must be an instance or subtype of type

これは、最初に、のインスタンス(またはサブタイプ)、つまりのsuper(__class__, self)をチェックするためです。ただし、インスタンスを渡しましたが、のサブクラスではありません。そのため、Python2のバインドされていないメソッドのエラーメッセージが役に立ちました。self__class__ABBA

于 2020-08-05T15:09:47.260 に答える