42

Python 3 のメソッド ラッパー タイプとは何ですか? 次のようにクラスを定義すると:

class Foo(object):
    def __init__(self, val):
        self.val = val
    def __eq__(self, other):
        return self.val == other.val

そして、次のようにします。

Foo(42).__eq__

私は得る:

<bound method Foo.__eq__ of <__main__.Foo object at 0x10121d0>>

しかし、もしそうなら(Python 3で):

Foo(42).__ne__

私は得る:

<method-wrapper '__ne__' of Foo object at 0x1073e50>

「メソッドラッパー」タイプとは何ですか?

編集: より正確に申し訳ありません:class method-wrapperのタイプ__ne__です。

>>> type(Foo(42).__ne__)
<class 'method-wrapper'>

のタイプ__eq__は次のとおりです。

>>> type(Foo(42).__eq__)
<class 'method'>

さらにmethod-wrapper、クラスの未定義のマジックメソッドのタイプのようです(明示的に定義されていない場合__le____repr____str__などにもこのタイプがあります)。

私が興味を持っているのは、method-wrapperクラスが Python でどのように使用されているかです。クラスのメソッドのすべての「デフォルト実装」は、このタイプの単なるインスタンスですか?

4

3 に答える 3

31

これは、「バインドされていないメソッド」が Python 3 に存在しないためです。

Python 3000 では、バインドされていないメソッドの概念が削除され、"A.spam" という式は単純な関数オブジェクトを返します。最初の引数が A のインスタンスでなければならないという制限は、問題の診断に役立つことはめったになく、高度な使用法の障害になることがよくあります --- 一部の人はそれを「ダックタイピングセルフ」と呼んでいますが、これは適切な名前のようです。 (ソース)

Python 2.x では、バインドされたメソッドとバインドされていないメソッドがありました。バインドされたメソッドはオブジェクトにバインドされました。つまり、メソッドが呼び出されたときに、オブジェクト インスタンスが最初の変数 (self通常は ) として渡されました。バインドされていないメソッドは、関数がメソッドであるが、それが属するインスタンスがないメソッドでした。オブジェクト インスタンス以外のものがメソッドに渡されると、エラーがスローされます。

3.x では、これが変更されました。バインド/非バインド メソッドの代わりに、オブジェクトのメソッドを要求すると、関数オブジェクトが返されますが、インスタンス変数を渡すラッパー関数にラップされます。この方法では、バインド メソッドと非バインド メソッドを区別する必要はありません。 - バインドされたメソッドはラップされますが、バインドされていないメソッドはラップされません。

違いを明確にするには:

2.x:

a = A()
f = A.method # f is an unbound method - you must pass an instance of `A` in to it as the first argument.
f = a.method # f is a bound method, bound to the instance `a`.

3.x:

a = A()
f = A.method # f is a function
f = a.method # f is a wrapped function with it's first argument filled with `a`.

a.method次のように考えることができます。

def method-wrapper():
    A.method(a)

詳細については、Guido のブログ ( the history of Python ) を参照してください。

編集:

したがって、これがすべて適用される理由は、ここで__ne__()はオーバーライドされていないためです。これはデフォルトの状態であり、C で実装された ID チェックです (980 行目)。ラッパーは、メソッドに上記の機能を提供するために存在します。

于 2012-05-03T14:56:49.060 に答える
-1

私の変数検査ルーチンからのいくつかのテストコードの下。__str__メソッドを持つ定義済みクラス Tst 。クラスのインスタンスに__repr__または__str__が定義されているかどうかを確認するには、次のことをテストできますhasattr(obj.__str__, '__code__')

例:

class Tst(object):
    """ Test base class.
    """
    cl_var = 15

    def __init__(self, in_var):
        self.ins_var = in_var

    def __str__(self):
        # Construct to build the classname ({self.__class__.__name__}).
        # so it works for subclass too.
        result = f"{self.__class__.__name__}"
        result += f"(cl_var: {self.__class__.cl_var}, ins_var: {self.ins_var})"
        return result

    def show(self):
        """ Test method
        """
        print(self.ins_var)


t5 = Tst(299)


print('\n\n----- repr() ------')
print(f"obj.repr(): {repr(t5)}")
print(f"obj.repr.class type: {type(t5.__repr__.__class__)}")
print(f"obj.repr.class.name: {t5.__repr__.__class__.__name__}")
print(f"obj.__repr__ has code: {hasattr(t5.__repr__, '__code__')}")

print('\n\n----- str() ------')
print(f"obj.str(): {str(t5)}")
print(f"obj.str.class type: {type(t5.__str__.__class__)}")
print(f"obj.str.class.name: {t5.__str__.__class__.__name__}")
print(f"obj.__str__ has code: {hasattr(t5.__str__, '__code__')}")

戻り値:

----- repr() ------
obj.repr(): <__main__.Tst object at 0x107716198>
obj.repr.class type: <class 'type'>
obj.repr.class.name: method-wrapper
obj.__repr__ has code: False


----- str() ------
obj.str(): Tst(cl_var: 15, ins_var: 299)
obj.str.class type: <class 'type'>
obj.str.class.name: method
obj.__str__ has code: True

__repr__はクラスで定義されていないため、デフォルトで を介して__repr__基本クラスに設定され、デフォルトの出力が得られます。 が定義されている (つまりメソッドである) ため、テストの結果は True になります。objectmethod-wrapper__str__hasattr(t5.__str__, '__code__')

于 2019-04-02T15:48:18.803 に答える