[Python] metalclass(元类)学习笔记

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,如有问题的话多多指出
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值