Python中的metaclass

来源:互联网 发布:apache subversion 编辑:程序博客网 时间:2024/06/08 00:44

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

原创粉丝点击