首页 > 技术文章 > 🍖元类(黑魔法)

songhaixing 2021-01-06 22:27 原文

引入

Python中一切皆对象, 那么本质上也是一个对象

87965

一.什么是元类

类既然也是对象, 那么就应该有另一个类来实例化得到它, 实例化得到类的类就是元类

默认情況下, 元类是 type 这个类, 并且所有的类都是由元类实例化得到的, 包括他自己

1.先定义一个类来进行分析

class Immortal(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

p = Immortal("太白",4555)
print(type(p))  # <class '__main__.Immortal'>

所有的对象都是通过 [类名] + ( ) 得到的, 也叫做实例化, p 对象就是由 Immortal 类实例化得到的

一切皆对象, 那么 Immortal 应该也是一个类实例化的结果, 于是我们可以推导出 元类+( ) ---> Immortal

print(type(Immortal))  # <class 'type'>
print(type(type))      # <class 'type'>

通过 type 函数我们发现 Immortal 的类就是 type 类, 并惊奇的发现 type 类的类是自身

461501

由此我们可以推断出 : 元类实例化得到类, 类实例化得到对象(实例), 并且验证了所有类都是由type实例化得到的, 不信你试试

1a5d63547a21b3dc2be4584c1a6ee70

二.分析class关键字创建类的过程

上面我们都是使用 class 这个关键字来产生类的, class 关键字在帮我们创建类的时候必然调用了 Immortal = type( ) 这种方法, 那么 type 里的参数应该是什么呢?

1.内置函数 exec 的用法

在分析 class 工作流程之前我们先来了解一下 exec 函数作为储备知识 : exec 有三个参数

  • 第一个参数是包含的要执行的一系列 Python 代码(字符串格式)
  • 第二个参数是全局名称空间 (字典形式), 默认为 globals( )
  • 第三个参数是局部名称空间 (字典形式), 默认为 local( )

作用 : 可以将字符串里内容当做Python语句来执行, 并将期间产生的名字存放于局部名称空间中

msg = '''
name = "shawn"
age = 22
dic = {"sex":"man"}
def test():
    print("I am shawn")
'''
globals_dic = {}  # 全局名称空间
locals_dict = {}  # 局部名称空间
exec(msg,globals_dic,locals_dict)

print(locals_dict) 
# {'name': 'shawn', 'age': 22, 'dic': {'sex': 'man'}, 'test': <function test at 0x000002596D9BC4C8>}
print(locals_dict["name"])  # shawn
locals_dict["test"]()       # I am shawn

2.调用 type + ( )来实现创建类

原来我们使用 class 来创建类, 其中必然调用了元类 type, type中需要传入三个参数, 这三个参数是类的三大组成部分 :

  • 类名 : Immortal = type( )
  • 父类们(基类们) : class_bases = (object , )
  • 类的名称空间 : class_namespace (类的名称空间是执行类体代码而得到的)

接下来我们开始动手创建一个类了

推荐阅读