likes
comments
collection
share

__new__特殊方法的使用

作者站长头像
站长
· 阅读数 59

__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__方法是在对象返回后执行的。

对象创建和实例化流程图

__new__特殊方法的使用

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
评论
请登录