str(super(B, b)) が super(B, b).__str__() と同等ではないのはなぜですか? 質問する

str(super(B, b)) が super(B, b).__str__() と同等ではないのはなぜですか? 質問する
  • Aが の親クラスでありBbが のインスタンスであると仮定しますB。この場合、 のオーバーライドされたメソッドはA次のように呼び出すことができます。素晴らしい: super(B, b).method().

  • ドキュメントにはこう記されている"str(object)戻り値object.__str__()"基本的な呼び出しにおいて。

そうなるべきですstr(super(B, b)) == super(B, b).__str__()が、そうではありません(インタラクティブバージョン):

class A:
    def __str__(self):
        return "A"


class B(A):
    def __str__(self):
        return "B"


b = B()   
b_super = super(B, b) 
print(str(b_super))       # "<super: <class 'B'>, <B object>>"
print(b_super.__str__())  # "A"

では、どこが間違っていたのでしょうか? スーパー メカニズムはマジック メソッドでは機能しないのでしょうか?この場合はstr呼び出されないのでしょうか? 次の段落に関連していますか:__str__

super()は、 などの明示的なドット属性検索のバインディング プロセスの一部として実装されていることに注意してください。super().__getitem__(name)これは、協調的な多重継承をサポートする予測可能な順序でクラスを検索する独自のメソッドを実装することによって行われます__getattribute__()。したがって、super()などのステートメントまたは演算子を使用した暗黙的な検索では、 は定義されませんsuper()[name]

ベストアンサー1

str()__str__通常の属性検索手順でメソッドを検索しません。代わりに、引数のクラス階層の__str__でメソッドを直接検索します。__dict__MRO順序。これにより が見つかりsuper.__str__、 が返されます"<super: <class 'B'>, <B object>>"

ただし、手動で検索する場合b_super.__str__、 は を通過しsuper.__getattribute__、フックは をsuper使用することで特別な属性検索動作を提供します。 を介した検索は__getattribute__に解決されA.__str__、それを呼び出します。

このクラスを検討してください。違いがわかると思います (そう願っています)。

class B(object):
    def __init__(self, other):
        self.other = other
    def __getattribute__(self, name):
        if name == 'other':
            return object.__getattribute__(self, 'other')
        elif name == '__str__':
            return getattr(self.other, name)
        else:
            return name
    def __str__(self):
        return 'fun'

>>> str(B(1))   # calls B.__str__ because it doesn't invoke __getattribute__
'fun'
>>> B(1).__str__()  # calls B.__getattribute__ to look up the __str__ method which returns (1).__str__
'1'

この場合の問題は、同様に、superこれらが転送を に依存するプロキシであることです__getattribute__。したがって、通過しない関数またはメソッドは__getattribute__転送されません。そして、str()はそのような関数です。


コメントと他の回答でも言及されていたので、完全を期すためです。

しかし、str(x)これはtype(x).__str__(x)なぜなら、str()クラス関数の通常の属性検索手順さえ回避できるからです。tp_str(またはNULLの場合はtp_repr) スロット。したがって、__getattribute__メタクラスを呼び出すことすらありません。メタクラスを呼び出すと、次type(x).__str__(x)のようになります。

class A(type):
    def __getattribute__(self, name):
        print(name)
        if name == '__str__':
            return lambda self: 'A'
        else:
            return type.__getattribute__(self, name)

class B(metaclass=A):
    def __str__(self):
        return 'B'

>>> b = B()
>>> str(b)
'B'
>>> type(b).__str__(b)
__str__
'A'

しかし、メタクラスがない場合、かもしれないstr(x)を と同等と考えると役に立ちますtype(x).__str__(x)。しかし、(潜在的には)役に立つとはいえ、それは正しくありません。

おすすめ記事