一、元类是什么?
在python中,一切皆对象,无论是列表、元组,还是函数、类,它们都是对象。
把一个类看作对象,即类对象,一个类对象的类就是元类。
通俗来说就是,元类是类的祖宗
可能这里描述的还是不清楚,下面举例解释:
首先我们用class 来检索一个对象对应的类
class main():
pass
print(main.__class__)
print(str.__class__)
>>>
<class 'type'>
<class 'type'>
上述代码中,无论我们自己创建的类main,还是‘str’,它们对应的类都是‘type’。
那‘type’本身对应的类是什么呢?
print(type.__class__)
>>>
<class 'type'>
结果‘type’对应的类还是‘type’。
这里,‘type’就是元类(类的祖宗,hah),创建其他类的类。
二、类type
那‘type’类到底有什么用呢?
可以查看下源码:
class type(object):
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
"""
- 获取一个对象的类型,这个很常用。
print(type('1234'))
print(type(1234))
>>>
<class 'str'>
<class 'int'>
- 定义一个新类型。
用法:
type(类名, 父类(可以为空),属性的字典(名称和值))
一个类必然包含以下三个部分:
- 类名
- 类的继承关系
- 类的属性
常规定义类的方法如下
class main():
first = True
使用type定义类:
main = type('main', (), {first:True})
使用type类可以创建其他的类,type类就是一个元类。
type不仅是其他类的元类,也是自己类的元类。
三、元类的作用
以上说明了元类是什么和type元类,那元类到底能干嘛?
(一)元类的作用区间
先说下创建类的过程,来说明元类在哪里起作用的。
一般定义类的时候,top函数是__init__,也就是初始化函数,但是实际上python中,实例化一个对象的过程,首先调用的是__new__函数,其次才是__init__函数。
__new__函数创建类的实例,并返回该实例,再调用__init__函数初始化实例,这样一个完整的实例就生成了。
class People(object):
def __init__(self, name, gender):
# 初始化实例
print(self)
print('init函数')
self.name = name
self.age = gender
def __new__(cls, *args, **kwargs):
# 创建实例,并返回实例
print(cls)
print(cls.__class__)
print('new函数')
obj = super().__new__(cls)
return obj
student = People('WWW', M)
>>>
<class '__main__.People'>
<class 'type'>
new函数
<__main__.People object at 0x000001E05919EEF0>
init函数
由返回结果可以看出在类创建时,先调用__new__函数创建了实例。·而元类type在__new__函数作用区间生成了类。
所以元类会控制类生成的过程,并在其中产生了影响。
下面就可以说它的作用了。
(二)元类的作用
1、手动创建类
如上面使用type元类手动创建一个新类。
main = type('main', (), {first:True})
2、自定义元类
定义一个新的元类,继承type,重新定义此类。
class MetaClass(type):
def __new__(cls, name, bases, attrs):
print(cls)
A = super(MetaClass, cls).__new__(cls, name, bases, attrs)
print(A)
return A
def __init__(self, *args, **kwargs):
super(MetaClass, self).__init__(*args, **kwargs)
print(self)
class P(object, metaclass=MetaClass):
pass
>>>
<class '__main__.MetaClass'>
<class '__main__.P'>
<class '__main__.P'>
增加__call__函数,可以控制实例对象的结果。
class MetaClass(type):
def __new__(cls, name, bases, attrs):
print(cls)
A = super(MetaClass, cls).__new__(cls, name, bases, attrs)
print(A)
return A
def __init__(self, *args, **kwargs):
super(MetaClass, self).__init__(*args, **kwargs)
print(self)
def __call__(self, *args, **kwargs):
B = super(MetaClass, self).__call__(*args, **kwargs)
print(B)
return B
class P(object, metaclass=MetaClass):
pass
if __name__ == '__main__':
a = P()
>>>
<class '__main__.MetaClass'>
<class '__main__.P'>
<class '__main__.P'>
<__main__.P object at 0x000002167148E668>
3、元类写单例模式
class MetaClass(type):
instance = None
def __call__(self, *args, **kwargs):
if self.instance is None:
self.instance = super(MetaClass, self).__call__(*args, **kwargs)
return self.instance
class P(object, metaclass=MetaClass):
pass
if __name__ == '__main__':
a = P()
b = P()
print(id(a), id(b))
if id(a) == id(b):
print('True')
>>>
1733009417272 1733009417272
True
4、使用元类动态编写类
class MetaClass(type):
def __new__(cls, name, bases, attrs):
if name == 'A':
attrs['add'] = lambda self, value: self.append(value)
else:
pass
return super(MetaClass, cls).__new__(cls, name, bases, attrs)
class A(list, metaclass=MetaClass):
pass
class B(list, metaclass=MetaClass):
pass
if __name__ == "__main__":
a = A()
a.add("123")
b = B()
print(a, b)
>>>
['123'] []