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

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()[name])的隐式查找,super()是未定义的.

推荐答案

str()不会通过常规属性查找过程查找__str__方法.相反,它在其参数的类层次 struct 的__dict__中按MRO顺序直接搜索__str__方法.结果是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()就是这样一个函数.


只是为了完整,因为 comments 和其他答案中提到了这一点.

But 102 isn't equivalent to 103因为str()甚至避免了"类上的函数"的常规属性查找过程.它只判断类的tp_str(如果为空,则判断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)是有帮助的.虽然(可能)有帮助,但这并不正确.

Python-3.x相关问答推荐

如何获得给定列表中所有可能的元素组合?

如何使用PySide6创建切换框架?

Django中自动设置/更新字段

如何根据索引子列表对元素列表进行分组或批处理?

为什么 Sympy 不能解决我的非线性系统? Python 解释器一直在执行,直到我终止进程

找到操作系统的图片文件夹的 CLI

BeautifulSoup 和 pd.read_html - 如何将链接保存到最终数据框中的单独列中?

如何从左到右解包元组?

逗号分隔列表的 argparse 操作或类型

创建日志(log)文件

cv2 python 没有 imread 成员

Asyncio RuntimeError:事件循环已关闭

Python:在 map 对象上调用列表两次

python setup.py egg_info mysqlclient

无论如何我可以在 Google colaboratory 中下载文件吗?

为什么 string.maketrans 在 Python 3.1 中不起作用?

带有自定义标头的 urllib.urlretrieve

在 macbook pro M1 上安装 Tensorflow 时出现zsh:非法硬件指令 python

Python 3中星型导入的函数形式是什么

三个参数的reduce函数