• 类的起源与metaclass


    一、概述

      我们知道类可以实例化出对象,那么类本身又是怎么产生的呢?我们就来追溯一下类的起源。

    二、类的起源

      2.1 创建一个类 

    class Foo(object):
    
        def __init__(self, name):
            self.name = name
    
    f = Foo('bigberg')
    
    # 我们创建一个 Foo的类
    # 实例化一个 对象  f
    

      在python中有个说法:一切皆为对象。如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

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

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

      2.2 type 创建类

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

    def func(self):      # 定义一个函数
        print('hello,world')
    
    Foo = type('Foo', (object,), {'talk': func})  # type创建类,(object,) 为元组
    
    f = Foo()
    f.talk()
    print(type(f))
    print(type(Foo))
    
    #  输出
    hello,world
    <class '__main__.Foo'>
    <class 'type'
    

      可以看到type 确实可以创建一个类,并且可以实例化对象

      那么我们如何传参呢?就需要我们自己写构造函数这些了: 

    def func(self):
        print('hello,%s' % self.name)
    
    
    def __init__(self, name):   # 构造函数
        self.name = name
    
    Foo = type('Foo', (object,), {'talk': func, '__init__': __init__})
    
    f = Foo('Bigberg')  # 传参
    f.talk() 
    
    # 输出
    hello,Bigberg
    

      So: 类 是由 type 类 实例化产生的

      

    三、__new__方法

      __new__() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在 Python 中存在于类里面的构造方法 __init__() 负责将类的实例化,而在 __init__() 启动之前,__new__() 决定是否要使用该 __init__() 方法,因为__new__() 可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例。  

    class Foo(object):
    
        def __init__(self, name):
            self.name = name
            print("in the Foo __init__")
    
        def __new__(cls, *args, **kwargs):  # 第一个参数cls,是当前正在实例化的类,这里是object
            print("Foo __new__", cls, *args, ** kwargs)
            return object.__new__(cls)  # 继承父类的__new__方法
    
    f = Foo('bigberg')
    print(f.name)
    
    # 输出
    
    Foo __new__ <class '__main__.Foo'> bigberg  # new方法先于init方法执行
    in the Foo __init__
    bigberg
    

    __new__() 方法的特性:

    • __new__() 方法是在类准备将自身实例化时调用。
    • __new__() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。

    注意:

      事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写__new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。

      如果我们不返回__new__()方法,无法进行实例化对象  

    class Foo(object):
    
        def __init__(self, name):
            self.name = name
            print("in the Foo __init__")
    
        def __new__(cls, *args, **kwargs):  object
            print("Foo __new__", cls, *args, ** kwargs)
            # return object.__new__(cls)  
    f = Foo('bigberg')
    print(f.name)
    # 输出
      File "G:/python/untitled/study6/类的起源.py", line 39, in <module>
        print(f.name)
    AttributeError: 'NoneType' object has no attribute 'name'
    

      

    四、__metaclass__方法 

      4.1 metaclass作用

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

     1 class MyType(type):
     2 
     3     def __init__(self, *args, **kwargs):
     4 
     5         print("Mytype __init__", *args, **kwargs)
     6 
     7     def __call__(self, *args, **kwargs):
     8         print("Mytype __call__", *args, **kwargs)
     9         obj = self.__new__(self)
    10         print("obj ", obj, *args, **kwargs)
    11         print(self)
    12         self.__init__(obj, *args, **kwargs)
    13         return obj
    14 
    15     def __new__(cls, *args, **kwargs):
    16         print("Mytype __new__", *args, **kwargs)
    17         return type.__new__(cls, *args, **kwargs)
    18 
    19 print('here...')
    20 
    21 
    22 class Foo(object, metaclass=MyType):
    23 
    24     def __init__(self, name):
    25         self.name = name
    26 
    27         print("Foo __init__")
    28 
    29     def __new__(cls, *args, **kwargs):
    30         print("Foo __new__", cls, *args, **kwargs)
    31         return object.__new__(cls)
    32 
    33 f = Foo("Bigberg")
    34 print("f", f)
    35 print("fname", f.name)
    36 
    37 
    38 #输出
    39 
    40 here...
    41 Mytype __new__ Foo (<class 'object'>,) {'__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x000002A1968FE8C8>, '__module__': '__main__', '__new__': <function Foo.__new__ at 0x000002A1968FE950>}
    42 Mytype __init__ Foo (<class 'object'>,) {'__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x000002A1968FE8C8>, '__module__': '__main__', '__new__': <function Foo.__new__ at 0x000002A1968FE950>}
    43 Mytype __call__ Bigberg
    44 Foo __new__ <class '__main__.Foo'>
    45 obj  <__main__.Foo object at 0x000002A196905898> Bigberg
    46 <class '__main__.Foo'>
    47 Foo __init__
    48 f <__main__.Foo object at 0x000002A196905898>
    49 fname Bigberg
    View Code

    创建过程如下:

      4.2 执行顺序

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

  • 相关阅读:
    spring子模块----->Spring Security------->相关教程(参考资料)
    Maven--->学习心得--->maven 概述
    Spring和Spring MVC 、Spring Security的关系
    leapMotion简介
    软件工程需求分析
    大型web网站-----系统架构
    Maven的安装与配置
    A Java Exception occured 解决
    mysql-5.7.20安装和配置
    线段树 poj 3667
  • 原文地址:https://www.cnblogs.com/bigberg/p/7256171.html
Copyright © 2020-2023  润新知