1. 什么是Python的类
在Python中,类是用于定义具有相同属性和方法的对象的模板。
类定义了该集合中每个对象所共有的属性和方法。对象是类的实例,类定义以关键字class开头,说的很抽象来个例子:
class Person(object):
def __init__(self):
self.name = "张三"
self.age = 18
obj = Foo()
这就是一个Python类的定义, __init__
是类的初始化方法,当一个类被实例化时(obj = Foo()
)会调用类的__init__方法
完成初始化,一个简单的类就完成了,那么还有没有其它方法来创建类呢,其实Python的类内部真正的创建是由type
来创建的
2.Python中的type
说到type
可能第一反应是用来判断对象类型
是用的,type
能创建类听着有点恍惚,是的,判断对象类型
是type
的一个作用,type
最大的作用却是动态创建类
2.1 如何使用type创建类
type('类名', (继承类,), {类方法或属性})
由上面不难看出type
接收三个参数,第一个是类名,第二个是继承类(可以是多个)已tuple的形式传入,可以是空元祖,默认继承object,第三个参数是一个字典,用来定义类属性和类方法,下面来点代码
class Person(object):
def __init__(self):
self.name = "张三"
self.age = 18
type_obj = type("Person", (object,), {"name": "张三", "age": 18})
print(type_obj)
print(Person())
输出:
<class '__main__.Person'>
<__main__.Person object at 0x109f487f0>
由此可见使用class
和type
在Python中都能定义一个类,那什么又是元类呢,继续往下
3.什么是元类
- 类是创建对象的模板(类->对象)
- 元类是创建类的模板 (元类->类)
其实我们上面说的type
它就是一个元类,那这样type
能够动态创建类就能说得通了,因为元类是创建类的模板
在Python中有着一切皆对象的说法,那么我们来看看一些代码片段
a = 13
b = "hello world"
c = [1, 2, 3, 4, 5]
d = {"name": "张三", "age": 18}
e = (1, 2)
def func():
print("hello world")
print(type(a))
print(type(b))
print(type(c))
print(type(d))
print(type(e))
print(type(func))
print(type(type))
print(type(object))
输出:
<class 'int'>
<class 'str'>
<class 'list'>
<class 'dict'>
<class 'tuple'>
<class 'function'>
<class 'type'>
<class 'type'>
看上述代码不难看出,在Python中常见的数据类型,函数其实都是类
包括类的鼻祖object
也是由type
创建的,甚至type
都是由自己创建
str:用来创建字符串对象的类。
int:是用来创建整数对象的类。
type:是用来创建类对象的类。
一个实例的类型,是类
一个类的类型,是元类
一个元类的类型,是type
4.怎么实现一个元类
先了解一下类中的三个很重要的魔法方法 __new__
、__init__
、__call__
__init__
: 类的初始化方法
__new__
: 类的构造方法,创建类,当实例化一个类时会调用这个方法
__call__
: 将类的实例对象变成可调用对象,简单理解,实例化一个类时,最先调用__call__
方法,在内部会先调用__new__
创建类,然后调用__init__初始化
知道了这个我们就来实现一个元类的实例
class TestMeta(type):
pass
class Person(metaclass=TestMeta):
def __init__(self, name="张三"):
self.name = name
obj = Person()
print(type(obj))
print(type(obj.__class__))
print(type(obj.__class__.__class__))
输出:
<class '__main__.Person'>
<class '__main__.TestMeta'>
<class 'type'>
先定义了一个TestMeta的元类,再定义了一个Person类继承了TestMeta元类,注意元类继承需要使用metaclass
实例化Person类时,看obj的类型就能看出来关系了
5.使用元类来写一个单例模式
class Metaclass(type):
_instance = None
def __call__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__call__()
return cls._instance
class Person(object, metaclass=Metaclass):
def __init__(self):
self.name = "张三"
obj = Person()
obj1 = Person()
print(obj)
print(obj1)
输出:
<__main__.Person object at 0x102125b40>
<__main__.Person object at 0x102125b40>
类是元类的实例,所以在创建一个普通类时,其实会走元类的 __new__
。
同时,我们又知道在类里实现了 __call__
就可以让这个类的实例变成可调用。
所以在我们对普通类进行实例化时,实际是对一个元类的实例(也就是普通类)进行直接调用,所以会走进元类的 __call__
注意事项:
当在实例化Person类时, Person类同时重写了__call__方法, obj = Person() 会调用元类的__call__方法,如果要使用Person类的__call__方法还需要obj()才能调用到重写的__call__方法
6.总结
- 理解了元类后建议去看看Django ORM的实现 会有更深的理解
- 部分参考:理解Python中的元类