Python 为什么str(super(B,B))与super(B,B)不等价?

Python 为什么str(super(B,B))与super(B,B)不等价?,python,python-3.x,inheritance,Python,Python 3.x,Inheritance,假设A是B的父类,B是B的实例。然后可以使用:super(B,B).method()调用被重写的A方法 文档在其基本调用中的状态 它应该遵循str(super(B,B))==super(B,B)。\uu str\uuu(),但事实并非如此(): A类: 定义(自我): 返回“A” B(A)类: 定义(自我): 返回“B” b=b() b_super=super(b,b) 打印(str(b#u super))“ 打印(b_super.uu str_uuuuuuuuuu())#“A” 那么我哪里

假设
A
B
的父类,
B
B
的实例。然后可以使用:
super(B,B).method()
调用被重写的
A
方法

  • 文档在其基本调用中的状态

  • 它应该遵循
    str(super(B,B))==super(B,B)。\uu str\uuu()
    ,但事实并非如此():

    A类:
    定义(自我):
    返回“A”
    B(A)类:
    定义(自我):
    返回“B”
    b=b()
    b_super=super(b,b)
    打印(str(b#u super))“
    打印(b_super.uu str_uuuuuuuuuu())#“A”
    
    那么我哪里出了问题?超级机制不适用于魔法方法吗?在这种情况下,
    str
    是否不调用
    \uuuuuuuu
    ?是否与本段有关:

    请注意,
    super()
    是作为显式虚线属性查找绑定过程的一部分实现的,例如
    super()。它通过实现自己的
    \uuu getattribute\uuu()
    方法来实现这一点,该方法用于以支持协作多重继承的可预测顺序搜索类。因此,
    super()
    对于使用语句或运算符(如
    super()[name]
    )的隐式查找是未定义的

    str()。相反,它在其参数的类层次结构的
    \uuuuu dict\uuuu
    中按顺序直接搜索
    \uuu str\uuuu
    方法。这会发现
    super.\uuuu str\uuuu
    ,它给出了

    但是,当您手动查找
    b\u super.\uu str\uuuuuuu
    时,通过
    super.\uuuu getattribute\uuuuuu
    ,钩子
    super
    用于提供其特殊的属性查找行为。通过
    \uuuu getattribute\uuuu
    进行的查找将解析为
    A.\uuuu str\uuuu
    ,并调用它

    以这门课为例,它说明了不同之处(我希望):

    这种情况下的问题以及
    super
    的问题是,这些代理依赖
    \uuu getattribute\uuu
    转发它。因此,任何未通过
    \uuu getattribute\uuuu
    的函数或方法都不会前进。而
    str()
    就是这样一个函数


    只是为了完整性,因为评论和其他答案中提到了这一点

    但是
    str(x)
    并不等同于
    type(x)。\uuuuu str\uuuuuuux)
    因为
    str()
    甚至避免了“类上的函数”的正常属性查找过程。它只检查类的插槽(如果为空)。因此它甚至不调用元类的
    \uuuuu getattribute\uuuuuu
    ,而
    type(x).\uuuu str\uuuuuuu(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).\uu str\uuuuuuuux)
    可能会有所帮助。但是,虽然(可能)有帮助,但这是不正确的。

    文档是错误的

    str(x)
    实际上相当于
    type(x)。\uuuu str\uuuuuux)

    如果您
    打印(键入(b_super).\uu str_uu(b_super))
    ,您会得到明显的结果


    (即使这在奇怪的元类中也可能过于简单)

    我相信这是因为
    super
    调用返回
    一个代理对象,该代理对象将方法调用委托给类型为
    的父类或同级类,该类有自己的
    \uuu str\uuuu
    ,不解析为“A”这是否也适用于其他类似的内置函数(例如,next)?你能给我指出一些详细阐述这一点的文件吗?还有,我想我应该问的是:有办法解决这个问题吗?因此,我不必调用super(B,B)。\uu str\uuu()?@tjanson是的,有几个内置函数绕过了
    \uuu getattribute\uuuu
    (请参阅上的文档中的注释)。但是没有完整的列表,只是提到它这样做是出于“性能原因”。@tjanson我不知道是否有办法解决这个问题。可能,但这并不是一件小事,因为您必须对内置的
    str
    函数进行猴子补丁,否则会弄乱内部结构。@tjanson关于解决方法:有一个补丁(来自Raymond Hettinger)提供了这一点。但它从未被合并,Guido声明,最好只记录在使用
    super
    实例时必须显式调用dunder方法。请参阅以了解来回。很抱歉,但是
    str(x)
    type(x)不等效。我更新了我的答案,以反映这一点(对于评论来说太长了)。
    
    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'
    
    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'