• 元类的简单了解


    一、什么是元类?

    在python中一切皆对象,那么类是否也是对象呢?通过class关键字产生的类的实例,我们已经很熟悉了,但是通过class关键字产生的类的类就是元类。

    class Bar:
        pass
    
    b1 = Bar()
    print(type(b1)) #<class '__main__.Bar'>
    
    print(type(Bar)) #<class 'type'>

    可以看到b1对象是由类Bar产生的,而Bar类是由type这个元类产生的,type是python中的一个内建元类。

    那么,使用class创建类时必然调用type元类,Bar=type(...),在type中也必定传入一些和类相关的参数,这就涉及类的组成部分了。

    类由三部分组成:

    • 类名 class_name='Bar'
    • 基类们 class_bases=(object,)
    • 类的名称空间 class_dict,类的名称空间是执行类体代码而得到的

    调用type时会依次传入以上三个参数,通过type创建Bar类的过程大致就是:

    (1)拿到类名 class_name='Bar'

    (2)拿到类的基类们 class_bases=(object,)

    (3)执行类体代码拿到类的名称空间 class_dict

    (4)调用元类得到Bar类,Bar = type(class_name,class_bases,class_dict)

    二、自定义元类

    像上面Bar没有声明自己的元类,那么默认它的元类就是type,除了内建type元类外,还可以通过继承type元类,然后使用metaclass关键字参数为一个类指定元类。

    (一)通过type元类实现类的创建

    通过上述Bar类的创建过程知晓type元类中传入三个参数:

    • Bar  表示需要创建的类的类名
    • (object,) 表示基类们
    • {} 一个字典,表示这个类中含有的属性和方法
    #属性
    name = 'Bright'
    #方法
    def hobby(self):
        print('write code!')
    #创建Bar类
    Bar = type('Bar',(object,),{'name':name,'hobby':hobby})
    #将Bar类实例化
    b1 = Bar()
    #测试
    print(b1.name)  #Bright
    print(b1.hobby) #<bound method hobby of <__main__.Bar object at 0x0000000000DC1BE0>>

     上面使用的就是基于最基本的内建元类type创建类,这与下面的直接使用class关键字创建的结果是相同的。

    class Bar:
        # 属性
        name = 'Bright'
    
        # 方法
        def hobby(self):
            print('write code!')
    
    #将Bar类实例化
    b1 = Bar()
    #测试
    print(b1.name)  #Bright
    print(b1.hobby) #<bound method Bar.hobby of <__main__.Bar object at 0x0000000000626898>>

    (二)自定义元类

    在自定义元类中使用到一个__call__方法,它是在对象后面加括号时调用,元类产生的对象就是我们常说的使用class创建的类,所以普通类的实例就相当于元类对象加括号。例如:

    b1 = Bar()

    b1是Bar类的实例,Bar是元类的实例,所以Bar()就默认执行了元类中的__call__方法。显然在__call__方法中就需要完成这么几件事:

    • 调用__new__方法创建一个空对象(就是b1)
    • 调用__init__方法初始化空对象
    • 返回初始化好的对象
    class MyType(type):
    
        def __call__(self, *args, **kwargs):
            #1、创建一个空对象,如果自己本身没有就去object中调用__new__
            obj = self.__new__(self) #传入的self就是类Bar
            #2、初始化空对象
            self.__init__(obj, *args, **kwargs) #相当于执行Bar.__init__(),self是MyType元类的实例Bar
            #3、返回这个初始化对象
            return obj
    
    class Bar(metaclass=MyType): #Bar = MyType(...)
        def __init__(self):
            pass
    
    b1 = Bar()
  • 相关阅读:
    Centos7 tomcat 启动权限
    Tomcat下post请求大小设置
    postgres安装时locale的选择
    flink 1.11.2 学习笔记(1)-wordCount
    prometheus学习笔记(3)-使用exporter监控mysql
    prometheus学习笔记(2)-利用java client写入数据
    mock测试及jacoco覆盖率
    shading-jdbc 4.1.1 + tk.mybatis + pagehelper 1.3.x +spring boot 2.x 使用注意事项
    prometheus学习笔记(1)-mac单机版环境搭建
    redis数据类型HyperLogLog的使用
  • 原文地址:https://www.cnblogs.com/shenjianping/p/11587765.html
Copyright © 2020-2023  润新知