metaclass在python里已经算深入的内容了,讲的人相对没那么多
## type
type可以用来查看一个实例是由什么类实例化出来的
但type还有一个功能:动态的定义一个类
先看看我们熟悉一些的方式:静态定义一个类
```python
class person:
pass
class student(person):
age: int = 0
```
这里student类等价于下面这种写法:
```python
type("student", (person,), {age: 0})
```
这是type动态地定义一个类的例子
第一个参数要求是一个str,代表这个类的名字
第二个参数是一个tuple,代表这个类继承了什么类
第三个参数是一个dict,代表这个类有哪些类属性
值得一提的是:***这里的student类是type的实例,而student类也可以产生自己的实例***
## metaclass
metaclass,实际上就是用我们自己写的类来创建student类。但是因为是我们自己写的类,我们可以做一些更灵活的事情:
```python
class myMeta(type):
def __new__(metacls, name, base, attrs):
pass
def __call__(cls, *args, **kwargs):
pass
myMeta("student", (person,), {age: 0})
```
metaclass一般继承type,通过重载__new__与__call__来实现我们自定义的type。
那这种```myMeta(...)```的写法其实比较丑,python提供了更好看的等价写法:
```python
class student(person, metaclass=myMeta):
age = 0
```
值得一提的是:```metaclass=```后面不一定要跟一个metaclass,也可以是一个返回一个class的function
## __new__
metaclass中的__new__对应着一个metaclass实例出一个class的过程。也就是说,当你写了```calss student(metaclass=myMeta)```之后,python会悄悄的把myMeta的__new__给运行了
下面给个简单的例子:
```python
class myMeta(type):
def __new__(metacls, name, base, attrs):
print("metaclass __new__")
return type.__new__(metacls, name, base, attrs)
class student(metaclass=myMeta):
def __init__(self):
print("class __init__")
if __name__ == "__main__":
print("Hello, world!")
student()
# metaclass __new__
# Hello, world
# class __init__
```
注意,meMeta的__new__如果使用super的话也需要把这四个参数都填进去
## __class__
还是以myMeta与student举例子
metaclass的__call__会在student类产生实例的时候被调用
```
class myMeta(type):
def __call__(cls):
print("metaclass __call__")
self = cls.__new__(cls)
self.__init__()
return self
class student(metaclass=myMeta):
def __init__(self):
print("class __init__")
if __name__ == "__main__":
print("Hello, world!")
student()
# Hello, world!
# metaclass __call__
# class __init__
```
# metaclass应用
你可能在简单的print中感受不到metaclass的强大
b站up 码农高天在他讲元类的视频中给出来了一个检测所有方法有没有test_开头的例子
metaclass还可以用来实现单例模式
django中用metaclass实现了简洁且强大的api
我还看到有用metaclass实现类似@dataclass的效果的代码
这些例子相信会让你惊艳的,但我写不动了……
那最后我想说的是,我推荐大家使用这样的编写方式:
```python
class myMeta:
pass
class father(metaclass=myMeta):
pass
class child(father):
pass
class child2(father):
pass
```
在python中,一个类首先会找自己有没有metaclass,如果没有,会去他的父类中寻找
个人认为像这么编写的话,会给class child_n的编写带来很多便利
最后,我也是初学metaclass,如有问题的话多多指出