zoukankan      html  css  js  c++  java
  • 类的实例化(过程)

    一、call

    对象后面加括号时,触发执行。
    注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,
    即:对象() 调用它的类的__call__
    或者 类() 调用它的元类的__call__

    class BBJ(type):#自定义元类必须继承type
        def __call__(self, *args, **kwargs):
            print(111)
    class Foo(metaclass=BBJ):#metaclass指定元类
        def __init__(self):
            print('__init__触发了')
        def __call__(self, *args, **kwargs):
            print('__call__触发了')
    Foo()  # 执行 __init__
    
    class Foo:
        def __init__(self):
            print('__init__触发了')
    
        def __call__(self, *args, **kwargs):
    
            print('__call__触发了')
    obj = Foo()  # 执行 __init__
    ===>__init__触发了
    obj()  # 执行 __call__
    ===>__call__
    

    二、init和new

    曾经我幼稚的以为认识了python的init()方法就相当于认识了类构造器,结果,new()方法突然出现在我眼前,让我突然认识到原来new才是老大。为什么这么说呢?

    我们首先得从new(cls[,…])的参数说说起,new方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给init方法初始化,这一下子就看出了谁是老子谁是小子的关系。

    所以,new方法(第一个执行)先于init方法执行:

    class A:
        pass
    
    
    class B(A):
        def __new__(cls):
            print("__new__方法被执行")
            return super().__new__(cls)
    
        def __init__(self):
            print("__init__方法被执行")
    
    
    b = B()
    ====>__new__方法被执行
    ====>__init__方法被执行
    
    

    我们比较两个方法的参数,可以发现new方法是传入类(cls),而init方法传入类的实例化对象(self),而有意思的是,new方法返回的值就是一个实例化对象(ps:如果new方法返回None,则init方法不会被执行,并且返回值只能调用父类中的new方法,而不能调用毫无关系的类的new方法)。我们可以这么理解它们之间的关系,new是开辟疆域的大将军,而init是在这片疆域上辛勤劳作的小老百姓,只有new执行完后,开辟好疆域后,init才能工作。

    绝大多数情况下,我们都不需要自己重写new方法,但在当继承一个不可变的类型(例如str类,int类等)时,它的特性就尤显重要了。我们举下面这个例子:

    class CapStr(str):
        def __init__(self, string):
            string = string.upper()
    
    
    a = CapStr("I love China!")
    print(a)
    ====>I love China!
    
    class CapStr(str):
        def __new__(cls, string):
            string = string.upper()
            return super().__new__(cls, string)
    
    
    a = CapStr("I love China!")
    print(a)
    =====>I LOVE CHINA!
    

    我们可以根据上面的理论可以这样分析,我们知道字符串是不可改变的,所以第一个例子中,传入的字符串相当于已经被打下的疆域,而这块疆域除了将军其他谁也无法改变,init只能在这块领地上干瞪眼,此时这块疆域就是”I love China!“。而第二个例子中,new大将军重新去开辟了一块疆域,所以疆域上的内容也发生了变化,此时这块疆域变成了”I LOVE CHINA!“。
    总结:

    在我们实例化一个类时,其实第一个调用的是类的元类的__call__,在这个__call__里面再调用类的__new__的到实例化的对象,然后调用类的__init__对对象进行初始化,最后将对象retrun出去,就得到我们的对象了
    
  • 相关阅读:
    poj 3068 Bridge Across Islands
    XidianOJ 1086 Flappy v8
    XidianOJ 1036 分配宝藏
    XidianOJ 1090 爬树的V8
    XidianOJ 1088 AK后的V8
    XidianOJ 1062 Black King Bar
    XidianOJ 1091 看Dota视频的V8
    XidianOJ 1098 突击数论前的xry111
    XidianOJ 1019 自然数的秘密
    XidianOJ 1109 Too Naive
  • 原文地址:https://www.cnblogs.com/qiukangle/p/14248135.html
Copyright © 2011-2022 走看看