• 面向对象【day08】:类的起源与metaclass(二)


    本节内容

    1、概述

    2、类的起源

    3、__new__方法

    4、__metaclass__方法

    一、概述

       前面我们学习了大篇幅的关于类,通过类创建对象,那我们想知道这个类到底是怎么产生的呢?它的一切来源是什么?还有对象,对象是通过什么方法创建的,现在我们一头雾水,行的,下面我们就来揭开类的面纱,看看类和对象到底是怎么创建的,通过什么创建的。

    二、类的起源

    2.1 传统创建类

    1
    2
    3
    4
    5
    class Foo(object):
        def __init__(self,name):
            self.name = name
     
    = Foo("shuaigaogao")

    f 是通过 Foo 类实例化的对象,其实,不仅 f 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象,按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

    1
    2
    print(type(f))    #输出:<class '__main__.Foo'>  表示:f 对象由Foo类创建
    print(type(Foo))  #输出:<class 'type'>          表示:Foo类对象由 type 类创建

    所以,f对象是Foo类的一个实例Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建 

    2.2 type创建类

    说明:  type创建类的格式,类名 = type('类名',(父类,),{'方法名':方法的内存地址})

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def func(self):  #创建方法
        print("hello {0}".format(self.name))
     
    def __init__(self,name):  #创建构造方法
        self.name = name
     
    #通过type创建类,如果是经典类的话则写成:Foo = type("Foo",(),{"talk":func,"__init__":__init__})
    Foo = type("Foo",(object,),{"talk":func,"__init__":__init__}) 
    = Foo("shuaigaogao")  #创建对象
    f.talk()
     
    #输出
    hello shuaigaogao

    总结:类 是由 type 类 实例化产生的

    值得注意的是,新式类的写法,在继承父类那边,你继承一个父类后面就要加一个逗号,加逗号,它就把它当做一个元组,不加逗号,就是一个值了

    三、__new__方法

    3.1 概念

    new方法是类自带的一个方法,可以重构,__new__方法在实例化的时候也会执行,并且先于__init__方法之前执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Foo(object):
     
        def __init__(self,name):
            self.name = name
     
            print("Foo __init__")
     
        def __new__(cls*args, **kwargs):
            print("Foo __new__",cls*args, **kwargs)
            return object.__new__(cls)
     
    = Foo("shuaigaogao")
     
    #输出
    Foo __new__ <class '__main__.Foo'> shuaigaogao  #执行了new方法
    Foo __init__  #执行了__init__方法

    3.2 new方法作用

    作用:所有对象都是通过new方法来实例化的,new里面调用了init方法,所以在实例化的过程中先执行的是new方法,而不是init方法。

    ①重构__new__方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Foo(object):
     
        def __init__(self,name):
            self.name = name
            print("Foo __init__")
     
        def __new__(cls*args, **kwargs):
            print("Foo __new__",cls*args, **kwargs)
     
    = Foo("shuaigaogao")  #实例化
     
    #输出
    Foo __new__ <class '__main__.Foo'> shuaigaogao

    由上面的例子看出,没有执行__init__方法

    ②重构__new__方法,并继承父类的__new__方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Foo(object):
     
        def __init__(self,name):
            self.name = name
     
            print("Foo __init__")
     
        def __new__(cls*args, **kwargs):   #cls相当于传入类Foo
            print("Foo __new__",cls*args, **kwargs)
            return object.__new__(cls)  #继承父类的__new__方法,这边必须以返回值的形式继承
     
    = Foo("shuaigaogao")
     
    #输出
    Foo __new__ <class '__main__.Foo'> shuaigaogao
    Foo __init__

    由上面不难看出,大多数情况下,你都不要去重构你的__new__方法,因为你父类中已经有__new__方法了,已经帮你写好了怎么去创建类,如果你重写的话,就会覆盖父类的里面的__new__方法。但是你重构可以增加一点小功能,但是你覆盖了以后还是需要继承父类回来,要不然你的这个实力就创建不了。

    3.3 使用场景

    我想对我自己写的一些类进行定制,就在它实例化之前就进行定制,就可以用到__new__方法,new方法就是用来创建实力的,重构new方法,必须以返回值的形式继承父类的new方法。

    ①需求:我在创建对象时候,同时创建一个类变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class Foo(object):
     
        def __init__(self,name):
            self.name = name
     
            print("Foo __init__")
     
        def __new__(cls*args, **kwargs):  #cls相当于是传入的类名Foo
            cls.name = "shuaigaogao"  #创建对象是定义静态变量
            print(cls.name)
            return object.__new__(cls)  #继承父类的__new__方法
     
    = Foo("shuaigaogao")
    print(Foo.name)
     
    #输出
    shuaigaogao
    Foo __init__
    shuaigaogao

    四、__metaclass__方法

    4.1 metaclass作用

    metaclass这个属性叫做元类,它是用来表示这个类是由谁来帮他实例化创建的,说白了,就是相当于自己定制一个类,就这么一个意思。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    class MyType(type):
        def __init__(self,*args,**kwargs):
     
            print("Mytype __init__",*args,**kwargs)
     
        def __call__(self*args, **kwargs):
            print("Mytype __call__"*args, **kwargs)
            obj = self.__new__(self)
            print("obj ",obj,*args, **kwargs)
            print(self)
            self.__init__(obj,*args, **kwargs)
            return obj
     
        def __new__(cls*args, **kwargs):
            print("Mytype __new__",*args,**kwargs)
            return type.__new__(cls*args, **kwargs)
     
    class Foo(object,metaclass=MyType):  #python3统一用这种
        #__metaclass__ = MyType  #python2.7中的写法
     
        def __init__(self,name):
            self.name = name
     
            print("Foo __init__")
     
        def __new__(cls*args, **kwargs):
            print("Foo __new__",cls*args, **kwargs)
            return object.__new__(cls)
     
    = Foo("shuaigaogao")
    print("f",f)
    print("fname",f.name)
     
    #输出
    Mytype __new__ Foo (<class 'object'>,) {'__new__': <function Foo.__new__ at 0x0000025EF0EFD6A8>,
    '__init__': <function Foo.__init__ at 0x0000025EF0EFD620>, '__qualname__''Foo''__module__''__main__'}
    Mytype __init__ Foo (<class 'object'>,) {'__new__': <function Foo.__new__ at 0x0000025EF0EFD6A8>,
     '__init__': <function Foo.__init__ at 0x0000025EF0EFD620>, '__qualname__''Foo''__module__''__main__'}
    Mytype __call__ shuaigaogao
    Foo __new__ <class '__main__.Foo'>
    obj  <__main__.Foo object at 0x0000025EF0F05048> shuaigaogao
    <class '__main__.Foo'>
    Foo __init__
    f <__main__.Foo object at 0x0000025EF0F05048>
    fname shuaigaogao

    创建过程如下:

    4.2 执行顺序

    类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__

    metaclass 详解文章:猛击这里 得票最高那个答案写的非常好

    作者:罗阿红 出处:http://www.cnblogs.com/luoahong/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
  • 相关阅读:
    Java语言
    Java面向对象编程思想
    final关键字
    abstract关键字
    对象初始化过程
    访问修饰符
    继承
    面向对象设计
    static
    封装
  • 原文地址:https://www.cnblogs.com/luoahong/p/9895485.html
Copyright © 2020-2023  润新知