为什么str(super(B,b))不等于super(B,b).__ str __()?

时间:2017-10-24 14:32:25

标签: python python-3.x inheritance

应该遵循super(B, b).method(),但事实并非如此(interactive version):

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()未定义。

2 个答案:

答案 0 :(得分:22)

str()没有通过常规属性查找过程查找__str__方法。相反,它以MRO顺序直接搜索其参数类层次结构的__str__中的__dict__方法。这会找到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()甚至避免了&#34;函数的正常属性查找过程类&#34 ;.它只检查该类的tp_str(或者该tp_repr的那个空)。所以它甚至不会调用元__getattribute__的{​​{1}} {/ 1}}:

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)。但虽然(可能)有帮助,但它不正确。

答案 1 :(得分:-1)

文档错了。

str(x) 实际等同于type(x).__str__(x)

如果你print(type(b_super).__str__(b_super)),你会得到明显的结果。

(即使在奇怪的元类的情况下,这可能过于简单)