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'