理解元类

元类

Python中我们可以实现类的动态创建,可以在执行函数时去选择创建一个类

def choose(foo):
    if foo == 'foo':
        class foo(object):
            pass
        return foo
    else:
        class boo(object):
            pass
        return boo
foo = choose('foo')
print(type(foo)) #output: <class 'type'>

然后用type()去查看foo的类型时发现它居然是type类型,type类型是什么类型,type不是Python的自省函数,用来查询类型的吗,比如这样

    def choose(foo):
            pass
    list = [1,2,3,4]
    print(type(list)) #<class 'list'>
    q = 10
    print(type(q)) #<class 'int'>
    print(type(choose)) #<class 'function'>

像这样,可以知道list的类型是list 整数类型是int 函数的类型是function,日常使用中也并没有见到type这样的类型,那搜一下type是啥吧,然后发现type其实是有两种用法的,一种用来自省,还有一种居然可以构建类具体用法如下

#参数1:是要生成的类名,
#参数2:是一个元组,用来继承父类
#参数3: 是一个字典,用来填写函数内容
foo = type('foo',(),{'bl':10})

print(foo) # <class '__main__.foo'>
print(type(foo)) # <class 'type'>

然后发现foo确实是被生成成一个类了,但他的类型也是type,一个类就是类嘛为什么是type呢,那我正常的去创建一个类去看看它到底是什么类型的

class demo():
    pass
print(type(demo)) # <class 'type'>

我的天结果还是type类型,难道Python中的类都是由type创建的吗,这个type太NB了吧

那接下来怎么办,这个元类到底是个啥呀,咱也不知道,咱也不敢说,咱也不敢问,那搜搜吧

搜到非常NB的一句话:

在Python中的所有东西都是对象

好像有道理啊,上面连类都可以像对象一样被创建,被操作,毫无作为类的威严啊,不是对象是啥,

如果它长得像对象,叫声像对象,走路也像对象,那它就是个对象

还有一句话:

type是一个元类

那所有的类还真是被type,创建的。那么类相当于是type的实例对象,创建出来的类也可以实例化
也就是说type是类的类,

好了咱明白,怪不得叫元类,元来是元始天尊的元啊,那咱就总结一下叫:

万类归元

使用元类

那它到底怎么用内,元类的主要用途就是在程序运行过程中去动态的对类进行修改,怎么去动态修改呢,
我们需要去定义一个元类A,然后去对__new__函数进行操作修改,那么当其他类去继承元类A的时候,那么其实就是执行了
元类A的__new__方法,然后这个元类A通过type函数去重新构建这个类,
比如要对一个类增加一个字段

#每个元类要继承type,type其实才是真 - 元类,或者type就叫元类,元类不是一类类,而是一个类,元类就是type(个人理解)
class MetaClassAdd(type):
    def __new__(mcs, name, base, dict):
        #这个dict包含了很多信息,要对其处理一下  
        #像是含有这样的信息<class 'dict'>: {'__module__': '__main__', '__qualname__': 'boo', 'id': 'jj'}
        #需要取boo类中的 id字段,将__开头的字段过滤掉                                
        attrs = ((name,value) for name, value in dict.items() if not name.startswith('__')
        mapping = dict((name, value) for name, value in attrs)
        mapping['key'] = 'value'
        return super(MetaClassAdd,mcs).__new__(mcs, name, base, dict)
class boo(metaclass=MetaClassAdd):
    id = 'jj'
b = boo()
print(b.key) # 输出value

像那么这样就可以做到了,
那么这里究竟发生了什么
其实这个很像是boo继承了MetaClassAdd,然后boo去调用 父类中的__new__ 去实现类的构建

在比如复杂一点的orm (下面只是一个简单的模型),先定义一个MetaClassModel元类

class MetaClassModel(type):
    def __new__(mcs, name, base, dct):
        if name == 'Model':
           return super(MetaClassModel, mcs).__new__(mcs, name, base, dct)
        attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
        mapping = dict((name, value) for name, value in attrs)
        
        for k in mapping:
            dct.pop(k)
        dct['__mapping__'] = mapping
        return super(MetaClassModel, mcs).__new__(mcs, name, base, dct)

这个类的作用是根据不同的userModel生成不同 mapping,

接着写 Model 类

#当然这是个假model
class Model(metaclass=MetaClassModel):
    def save(self):
        for k, v in self.__mapping__.items():
            print(k, v)

对数据增,删,改,查

然后User类

class User(Model):
    id = 1
    name = 'll'
    sex = 'll'
class good(Model):
    id = 1
    price = 100
    count = 100
    
usr = User()
good = good()
good.save()
usr.save()

这样用元类实现一个非常简单的orm

用元类实现 单例模式,为什么元类可以实现单例内,前面说过类也是对象,当在一堆实例面前,类是类
但在type面前就是个对象弟弟。

class Singleton(type):
    def __init__(cls, name, base, dct):
        super(Singleton, cls).__init__(name, base, dct)
        cls._instance = None
    def __call__(self, *args, **kwargs):
        if self._instance == None:
            self._instance = super(Singleton, self).__call__(*args, **kwargs)
        return self._instance

class boo(metaclass=Singleton):
    pass
f = boo()
b = boo()
print(f is b) #true

Singleton去生成一个实例类boo,在其创建boo时加入一个标记,那么下面boo去生成实例对象的时候就要去Singleton中去找__call__函数
这样就控制了boo实例的创建,保证每次创建的对象只有一个

上一篇:[ML L9] Clustering (K-MEANS)


下一篇:JavaScript import&export