由于str.__call__我显然不理解的行为,我遇到了对str类进行子类型化的问题.
下面的简化代码可以很好地说明这一点.
class S(str):
def __init__(self, s: str):
assert isinstance(s, str)
print(s)
class C:
def __init__(self, s: str):
self.s = S(s)
def __str__(self):
return self.s
c = C("a") # -> prints "a"
c.__str__() # -> does not print "a"
str(c) # -> asserts fails in debug mode, else prints "a" as well!?
Run Code Online (Sandbox Code Playgroud)
我一直认为str(obj)函数只是调用obj.__str__方法,就是这样.但由于某种原因,它也再次称之为__init__功能S.有人可以解释这种行为以及如何避免在使用该函数时S.__init__调用的结果吗?C.__str__str()
严格来说,str不是一个功能.这是一种类型.当您调用时str(c),Python会通过正常的过程来生成类型的实例,调用str.__new__(str, c)以创建对象(或重用现有对象),然后调用__init__结果的方法来初始化它.
str.__new__(str, c)调用C级函数PyObject_Str,该函数调用_PyObject_Str调用__str__方法.结果是一个实例S,因此它被视为一个字符串,并_PyObject_Str确定这是足够好的,而不是试图强迫一个对象type(obj) is str超出结果.因此,str.__new__(str, c)回报c.s.
现在我们来了__init__.由于参数为stris c,因此也会传递给__init__Python,因此Python调用c.s.__init__(c).__init__调用print(c),你可能认为会调用str(c)并导致无限递归.但是,PRINT_ITEM操作码调用C级PyFile_WriteObject来编写对象,并且调用PyObject_Str而不是str,因此它会跳过__init__并且不会无限递归.相反,它调用c.__str__()并打印生成的S实例,因为S实例是一个字符串.
| 归档时间: |
|
| 查看次数: |
91 次 |
| 最近记录: |