继承str类时未传参数的super().__init__()为何能正常工作?
我出于学习目的尝试继承str类,编写了两种构造方法实现:
实现1:使用super().init()
class Str2(str): def __init__(self, value): super().__init__() # 未传入value,但代码可正常运行! def ishello(self): if self == "Hello": return True else: False s = Str2("Hello") print(s.upper()) # 输出: HELLO print(s.ishello()) # 输出: True
实现2:直接调用str.init(value)
class Str2(str): def __init__(self, value): str.__init__(value) # 这种实现符合我的预期 def ishello(self): if self == "Hello": return True else: False s = Str2("Hello") print(s.upper()) # 输出: HELLO print(s.ishello()) # 输出: True
核心疑问:第一种实现中,未传入value的super().__init__()为何能正常工作?
解答
这要从Python中不可变类型的实例创建逻辑说起:
__new__与__init__的分工
Python创建对象时,先调用__new__方法生成实例(分配内存并初始化实例的核心数据),之后才会调用__init__方法做后续初始化。对于str这类不可变类型,实例的核心值(比如你传入的"Hello")是在__new__阶段就设置完成的,__init__方法几乎没有实际作用。str.__init__的实际行为
str的__init__方法是空实现,它不需要接收除self之外的参数——因为实例内容已经在__new__阶段初始化完毕。所以不管你调用super().__init__()还是super().__init__(value),甚至完全不调用父类__init__,都不会影响实例的内容。第二种实现的误区
第二种写法str.__init__(value)其实是错误的:__init__的第一个参数必须是实例本身(self),这里把value作为第一个参数传入,相当于把字符串"Hello"当成了self,只是因为str.__init__什么都没做才没报错,正确的调用应该是str.__init__(self)或者super().__init__()。
总结来说,第一种实现能正常工作,是因为str的实例初始化根本不在__init__里完成,__init__在这里只是个“空架子”,传不传value都不影响已经通过__new__创建好的实例内容。
内容的提问来源于stack exchange,提问作者Park

