一,前言
在python的面向对象中我们可以给实例化出来的对象添加属性,这大大的提高了语言的灵活性。但是我们也知道python中的一切皆对象,我们可以通过__new__方法来控制对象的创建。那么,我们可不可以控制类的创建呢,答案是可以的,接下来我们去一探究竟。
二,什么是元类
元类:用来创建类的类。你创建类就是为了创建类的实例对象, 但是我们已经学习到了Python中的类也是对象 元类就是用来创建这些类(对象)的,元类就是类的类。
三,元类详解
上节说道,类是由元类创建的,那么谁是元类。可不可以自己定义元类。答案也是可以的。
3.1 type()元类
众所周知,我们可以用type()方法来查询某个对象的类型,也可以用object.__class__来查看对象的类型如下所示:
class A(object): pass a = A() print(type('str'), 'str'.__class__.__class__) print(type(a), a.__class__.__class__) print(type(A), a.__class__.__class__)
输出结果:
<class 'str'> <class 'type'> <class '__main__.A'> <class 'type'> <class 'type'> <class 'type'>
从结果中可以看出,类的类就是type,其实type就是python中的内建的元类。是它创建了类。那可不可以自己创建一个元类你,答案也是可以的
3.2 用type来创建类
我们知道,type可以创建类,接下来我们就用type这个元类来创建一个类。如下代码
# 类名 = type(类名, 父类元组, 属性字典) A = type('A', (object, ), {'a': 1}) a = A() print(a.a)
四,__metaclass__
4.1 __metaclass__介绍
我们自己在创建类时可能很少用到__metaclass__这个属性,但是当你用到时Python就会用元类来创建类Foo。需要注意的是,如果仅仅是写下class A(object),其实类Foo还没有在内存中创建。Python 首先会在类的定义中寻找__metaclass__属性,如果找到了,Python就会用它来创建类A,如果没有找到,就会使用内建的type来创建这个类。当你写如下代码时 :
class A(object): pass
python要创建该类,会经过以下步骤:
- 查看A中是否有__metaclass__属性?如果是,Python会通过 __metaclass__创建名字为A的类(也可以理解为对象, 一切皆对象)
- 如果Python没有找到__metaclass__,它会继续在其父类中寻找 __metaclass__属性,并尝试做和之前同样的操作。
- 如果Python在任何⽗类中都找不到__metaclass__,它就会在模块层次 中去寻找__metaclass__,并尝试做同样的操作。
- 如果还是找不到__metaclass__,Python就会用内置的元类type来创建这个类对象。
从上面的步骤我们就会得出一个问题,__metaclass__怎么使用,里面可以放一些什么东西呢?
4.2 定义元类
在使用元类时,首先得明白,__new__返回的是一个对象,它的调用在__init__之前。
使用元类主要的目的就是为了在创建类的时候,可以动态的改变它,提高代码的灵活性,特别是在一些API中,无法明确类的属性时非常实用。接下来我们就来试一下,如何定义一个元类:
class A(type): def __new__(cls, *args, **kwargs): print(cls) print(*args) return type(*args, **kwargs) class B(object, metaclass=A): bar = 'ccc' b = B()
输出结果:
<class '__main__.A'> B (<class 'object'>,) {'__module__': '__main__', '__qualname__': 'B', 'bar': 'ccc'}
从上面的代码可知,在我们对对象B进行实例化时会经过如下步骤:
- python加载B类时,发现有metaclass属性,该属性就是A就知道,该类需要通过A来创建。就会去找A。
- 我们知道type创建类时,需要(类名,父类元组,类的属性字典),python就会加载这些需要的内容,并将其封装成一个元组,传给A。
- A接收到这些参数,就可以对其进行创建
当然,上面的代码还有以下改写方式:
class A(type): def __new__(cls, *args, **kwargs): print(cls) print(*args) # return type(*args, **kwargs) # 直接用type创建 # return type.__new__(cls, *args, **kwargs) # 用父类的__new__方法进行创建 return super(A, cls).__new__(cls, *args, **kwargs) # 用继承的方式进行创建 class B(object, metaclass=A): def __init__(self, a): self.a = a b = B(1)
4.3 元类的高级用法
下面,就是一个元类的实例,动态的类添加一个方法:
def fun(self): # 定义需要添加的属性 print('fun test ....') class A(type): def __new__(cls, *args, **kwargs): """ :param args: (B, (object, ), {'__init__': <B.function object>}) # 根据上面args的参数因为 :param kwargs:{} :return: """ if 'fun' not in args[2].keys(): # 若fun不存在,则添加fun函数 args[2]['fun'] = fun return type(args[0], args[1], args[2]) class B(object, metaclass=A): def __init__(self, a): self.a = a b = B(1) print(hasattr(b, 'fun')) # 判断是否有fun b.fun() # 调用
五,总结
1,元类是用来创建类的,是祖宗类。
2,使用元类可以增加类创建的灵活性,在创建类时动态的添加属性。
3,python内建的元类是type