元类
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实例的创建,保证每次创建的对象只有一个