__new__特殊方法的使用
__new__特殊方法的使用
首先,需要区分出__new__方法和__init__方法的区别,区别在于一个是用来创建对象,一个是用来初始化对象的。
使用__new__创建对象
class Father:
def __new__(cls, *args, **kwargs):
print("__new__方法被执行了")
mcls = super().__new__(cls, *args, **kwargs)
return mcls
def __init__(self):
print("__init__方法被执行了")
F = Father()
# __new__方法被执行了
# __init__方法被执行了
从这里可以看到__new__方法的执行是要早于__init__方法的执行的,那么接下来就要考虑这两个方法是在什么情况下执行的,已经如何执行的。
__new__在创建对象时执行
什么是创建对象?就是F = Father()
,当时看到这里,个人是有点混乱的,在我的理解中F = Father()
应该被称为实例化对象,就是执行__init__方法把一个类进行实例化,为什么这里又叫做创建对象呢?查阅了一些文档,然后加入了一些个人的理解,其实F = Father()
应该是做了两步操作,第一步是先把对象创建出来,第二步才是把创建出来的对象通过__init__方法来完成实例化,接下来我将通过两步来验证我的一个观点是否准确。
__new__是如何创建对象的
这里也可以称为:为什么说__new__创建了对象
class Father:
def __new__(cls, *args, **kwargs):
mcls = super().__new__(cls) # 这里是向上调用父类的__new__方法,也是要通过调用完所有父类的__new__方法后才能创建出对象
print(f"__new__创建的对象id:{id(mcls)}")
return mcls
F = Father()
print(f"实例对象F的id:{id(F)}")
# __new__创建的对象id:1374367889392
# 实例对象F的id:1374367889392
从这里的打印结果可以看到,对象确实是由__new__方法创建的,且是通过__new__方法返回的,那么如果__new__没有返回值,就没有这个对象呢?F是不是就无法使用呢?
class Father:
def __new__(cls, *args, **kwargs):
mcls = super().__new__(cls) # 这里是向上调用父类的__new__方法,也是要通过调用完所有父类的__new__方法后才能创建出对象
print(f"__new__创建的对象id:{id(mcls)}")
# return mcls
def run(self):
print("hello")
F = Father()
print(f"实例对象F的id:{id(F)}")
print(F)
F.run()
# __new__创建的对象id:2255417161712
# 实例对象F的id:140723402549488
# None
# AttributeError: 'NoneType' object has no attribute 'run'
通过这段代码,我们其实已经可以确定了,对象确实是由__new__方法创建和返回的,可以尝试解开return mcls
这行的注释,发现程序没有异常了,这是因为对象被返回了。
__init__是在何时执行的?
class Father:
def __new__(cls, *args, **kwargs):
print("__new__方法执行了")
mcls = super().__new__(cls) # 这里是向上调用父类的__new__方法,也是要通过调用完所有父类的__new__方法后才能创建出对象
return mcls
def __init__(self):
print("__init__被执行了")
F = Father()
# __new__方法执行了
# __init__被执行了
再来回顾一下这段代码,可以很明确的知道,__init__方法一定是在__new__方法之后运行的,也就是实例化方法一定是在创建对象之后运行的,但是是在哪个阶段运行的呢?是在创建对象中间?也就是mcls = super().__new__(cls)
,还是在创建对象之后呢?对此,我们可以通过__new__方法不返回,也就是对象不创建来验证,__init__方式是在哪个阶段运行的。
如果__new__没有返回对象,但是__init__却执行了,就可以确定实例化是在
super().__new__(cls)
执行的,如果没有,则证明实例化是在__new__返回对象后在执行的
class Father:
def __new__(cls, *args, **kwargs):
print("__new__方法执行了")
mcls = super().__new__(cls) # 这里是向上调用父类的__new__方法,也是要通过调用完所有父类的__new__方法后才能创建出对象
# return mcls
def __init__(self):
print("__init__被执行了")
F = Father()
# __new__方法执行了
通过这段代码的执行,我们可以清楚的理解到,__init__方法是在对象返回后执行的。
对象创建和实例化流程图
cls是啥?和self有啥区别?
首先,cls是一个变量,指代类本身,其次,cls只是通用的一个名称,变量名是可以任意改变的
class Father:
def __new__(self, *args, **kwargs):
print("__new__的cls", self)
mcls = super().__new__(self) # 这里是向上调用父类的__new__方法,也是要通过调用完所有父类的__new__方法后才能创建出对象
return mcls
def __init__(self):
pass
F = Father()
print("对象Father", Father)
# __new__的cls <class '__main__.Father'>
# 对象Father <class '__main__.Father'>
这里将变量名cls改为了self,仍然可以正常运行,所以cls指代的是创建对象时的第一个参数,用来指代类本身,那么__init__方法中的第一个参数self是什么呢?跟cls有什么区别呢?两个变量名称一样会不会被混淆呢?
class Father:
def __new__(self, *args, **kwargs):
print("__new__的cls", self)
mcls = super().__new__(self) # 这里是向上调用父类的__new__方法,也是要通过调用完所有父类的__new__方法后才能创建出对象
return mcls
def __init__(self):
print("__init__的self", self)
F = Father()
print("对象Father", Father)
print("实例化对象F", F)
# __new__的cls <class '__main__.Father'>
# __init__的self <__main__.Father object at 0x00000243D209B820>
# 对象Father <class '__main__.Father'>
# 实例化对象F <__main__.Father object at 0x00000243D209B820>
通过这里我们可以看到,创建对象和实例化对象时,参数名称一致不会出现任何问题,同时也可以看到,cls指的是类本身,而self指的是类的对象。
class A:
def __init__(self):
self.num = 10
print("A的__init__方法执行了")
def run(self):
print("hello")
def count(self):
return self.num
B = A()
class Father:
def __new__(cls, *args, **kwargs):
print("Father的__new__方法执行了")
mcls = super().__new__(A)
# mcls = super().__new__(B)
return mcls
def __init__(self):
print("__init__的self", self)
F = Father()
F.run()
# F.count()
# A的__init__方法执行了 在B = A()处的打印
# Father的__new__方法执行了
# hello
这段代码主要为了证明两个问题,第一、cls代表的是类,而不是类的实例,self才是。第二、如果__new__的是其他的类,那么对象仍然可以正常创建,但是无法初始化(一般人也不会这么写)
关于父类的__new__方法
父类都必须有返回,否则对象无法创建 创建子类对象时,会一层一层执行父类的__new__方法 即使某个父类没有__new__方法,但是上一级中有,也会执行到
class A:
def __new__(cls, *args, **kwargs):
print("A的__new__方法执行了", cls)
cls = super().__new__(cls)
return cls
class B(A):
def __new__(cls, *args, **kwargs):
print("B的__new__方法执行了", cls)
return super().__new__(cls)
class C(B):
def __init__(self):
print("C的__init__方法执行了")
class D(C):
def __new__(cls, *args, **kwargs):
print("D的__new__方法执行了", cls)
cls = super().__new__(cls)
return cls
class E(C):
def __init__(self):
print("E的__init__方法执行了")
d = D()
print(d)
print("------------------------")
e = E()
print(e)
# D的__new__方法执行了 <class '__main__.D'>
# B的__new__方法执行了 <class '__main__.D'>
# A的__new__方法执行了 <class '__main__.D'>
# C的__init__方法执行了
# <__main__.D object at 0x0000014FA5F99130>
# ------------------------
# B的__new__方法执行了 <class '__main__.E'>
# A的__new__方法执行了 <class '__main__.E'>
# E的__init__方法执行了
# <__main__.E object at 0x0000014FA5F995E0>
这段代码有效的证明了__new__方法的一个执行流程,通过,如果注释掉任意一个父类__new__的return,则对象一定为空,如果子类中没有__init__方法时,会执行离子类最近的父类的__init__方法来实现初始化。
转载自:https://juejin.cn/post/7377230203153825802