昨天偶然在一篇博客中看到关于 __new__ 和 __init__ 的一道题目,发现不太理解,于是搜了一下相关资料学习一下。
然后在博客园一篇博文评论区,与一位博主讨论了很多次,
链接 : Python中__new__的作用
想要弄清楚这两个方法具体的运行顺序以及机制 ,于是就写了一个简单的测试例子:
python版本:3.7
class PositiveInteger(int):
def __init__(self, value):
print('init', value)
# 没有返回值 , 只是为了对照
super_init = super(PositiveInteger, self).__init__()
print('super_init', super_init)
def __new__(cls, value):
print('new', value)
value += 1
super_new = super(PositiveInteger, cls).__new__(cls, value)
print('super_new', super_new)
return super_new
class PositiveInteger2(PositiveInteger):
def __init__(self, value):
print('init2', value)
# 没有返回值 , 只是为了对照
super_init2 = super(PositiveInteger2, self).__init__(abs(value))
print('super_init2', super_init2)
def __new__(cls, value):
print('new2', value)
value += 1
super_new2 = super(PositiveInteger2, cls).__new__(cls, value)
print('super_new2', super_new2)
return super_new2
i = PositiveInteger2(-3)
print(i)
运行结果:
new2 -3
new -2
super_new -1
super_new2 -1
init2 -3
init 3
super_init None
super_init2 None
-1
这个例子可以很清晰追踪到,两个方法的执行顺序 ,以及继承时的调用顺序。
可以得出几点结论:
1. 声明对象时 , 会分别调用 __new__() 和 __init__() 方法 ,
2. 虽然__new__()先执行 , 但两个方法的入参变量是同一个对象 , __new__()中对入参进行二次赋值 , 并不会影响__init__()方法的入参对象值
3. 由于第二点 , 所以两个方法的入参数量需保持一致
4. __new__()方法创造了对象的实例并返回,而__init__() 方法作为构造方法对成员变量(局部变量) 进行操作 , __new__() 中无法触达局部变量 ( 这点在代码中没有显示 , 可以随便添加一个局部变量 , 在__new__() 调用试试看 , 编译器会报错 )
果然语言是想通的 , python的这种机制 , 和java的new关键字与类构造方法的关系很相似。