Python中的metaclass

Python中的metaclass

我们知道,当一个类定义了,那么类其中的成员变量和函数也就确定了。而metaclass就是一种在运行时动态设置成员变量和函数的一种方法

type()函数

type(name, bases, dict)
类名称(name)、父类列表(bases)和 属性字典(dict) “

python中一个类的定义可以通过 class 类名(父类)来定义,同样可以通过上面的type函数形式定义

>>> class user(object):
...     user = "user"
...     key = "key"
...
>>> print(user)
<class '__main__.user'>
>>> u = user()
>>> u.user
'user'
>>> u.key
'key'

再看使用type定义

>>> user = type("user",(),{"name":"user","key":"123456"})
>>> u = user()
>>> u.name
'user'
>>> u.key
'123456'

其中可以看到user类中成员函数和变量都是用dict存放的,那么,我们只需要动态的改变dict中的内容就对应修改了这个类的成员变量和函数

metaclass 类

定义一个类,表示用此类或子类的定义的变量是可以改变的

class Field(object):
    def __init__(self,):
        pass

再定义几个子类,同样用这些类定义的变量都是可以改变的

class IntegerField(Field):
    def __init__(self):
        super(IntegerField, self).__init__()

class StringField(Field):
    def __init__(self):
        super(StringField, self).__init__()

定义三个成员变量,其中两个是可以改变的

class User(Model):
    age = 20
    name = StringField()
    sex = IntegerField()

此处到了重点,什么是元类,元类就是创建类的类。也可以说他就是一个类的创建工厂,如 type 函数。
User 中有__metaclass__这个属性吗?如果有,那么Python会在内存中通过__metaclass__创建一个名字为User 的类对象。如果Python没有找到__metaclass__,它会继续在自己的父类Model中寻找__metaclass__属性,并且尝试以__metaclass__指定的方法创建一个User 类对象。如果Python在任何一个父类中都找不到__metaclass__,它也不会就此放弃,而是去模块中搜寻是否有__metaclass__的指定。如果还是找不到,那就是使用默认的type来创建User

class Model(dict, metaclass=ModelMetaclass):
    def __init__(self, **kw):
        super(Model, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Model' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

注意到模块集成自dict,有__getattr____setattr__方法,那么只要将任意变量名的成员赋值,就相当于为类添加了成员函数

class ModelMetaclass(type):
    # __new__方法接受的参数依次是:
    # 1.当前准备创建的类的对象(cls)
    # 2.类的名字(name)
    # 3.类继承的父类集合(bases)
    # 4.类的方法集合(attrs)
    def __new__(cls, name, bases, attrs):
        # 排除Model类本身:
        if name == 'Model':
            return type.__new__(cls, name, bases, attrs)
        # 获取所有的Field和主键名:
        mappings = dict()
        fields = []
        for k, v in attrs.items():
            if isinstance(v, Field):
                mappings[k] = v
        # 删除成员变量重新构造
        for k in mappings.keys():
           attrs.pop(k)
        return type.__new__(cls, name, bases, attrs)

注意:
其中,attrs.pop(k)将我们事先定义好的成员变量删除,那么起始状态,其中并没有name和sex字段
由于Model集成自dict,User也继承自dict。之前提到过,类的成员变量和函数都是以dict存放,这样ModelMetaclass类__new__函数中传入的参数attr就是它自生,那么当我们往Model中添加数据时,相当于给User添加成员变量

u1 = User(name="user",sex=1)    #添加了name和sex字段
u2 = User(name="user")          #只添加了name字段
u3 = User(sex=1)                #只添加了sex字段

[参考]:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319106919344c4ef8b1e04c48778bb45796e0335839000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值