python中的元类和abc.ABCMeta实现的虚类
一、元类
要理解元类,需要先理解python中的类,用class修饰的都可以叫做类,例如
class Class():
pass
c = Class()
print(c)
<__main__.Class object at 0x00000221E277EBE0>
而在python中远远不止于此,众所周知在python中“一切”皆是对象,注意是“一切”,也就是说类本身也是一个对象,你可以直接打印类本身,例如
Class
Out[45]:
__main__.Class
你可以为类本身增加属性
c = Class()
Class.b = 2
c.b
Out[51]:
2
我们平时用的类都是实例化以后的类,可以在任何时候动态的创建类,通常情况我们都是这样c=Class(),python解释器会将它认为是创建类,可是解释器本身是如何创建类的,答案是利用type
type平时我们可能认为是查看对象的类型,例如
type(c)
Out[52]:
__main__.Class
那么Class的类型是什么呢?
type(Class)
Out[53]:
type
看到没,Class的类型是type
我们可以用type直接生成一个类
type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
type('Class_type',(),{'a':1,'b':2})
Out[55]:
__main__.Class_type
Class_type = type('Class_type',(),{'a':1,'b':2})
c_t = Class_type()
c.a
Out[58]:
1
到这里,可以引入元类了,什么是元类
元类就是用来创建这些类(对象)的类,元类就是类的类
type就是所有类的元类,可以理解为所有的类都是由type创建的
我们也可以创建自己的元类,这个类需要继承自type
__metaclass__属性
当我们定义了__metaclass__属性的时候,解释器会做些什么呢
例如我们定义了
class Test(Base):
pass
Class中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__创建一个名字为Test的类对象
如果Python没有找到__metaclass__,它会继续在Base(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。
如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。
如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。
那么__metaclass__是啥东西呢?
答案就是可以创建类的东西,前面提过,类是由type创建的,所以__metaclass__内部一定要返回一个类,它可以是一个函数,也可以是一个类,而这个类就是我们自定义的元类,这个类必须继承自type
如果是个函数:例如我们想把类的所有属性变成大写
def upper_attr(future_class_name,future_class_parent,future_class_attr):
attrs = ((name,value) for name,value in future_class_attr.items() if not name.startswith('__'))
uppercase_attr = dict((name.upper(),value) for name,value in attrs)
#通过type创建类对象
return type(future_class_name,future_class_parent,uppercase_attr)
class Test(object,metaclass=upper_attr):
a = '1'
当然我们也可以定义自己的元类来实现这一动作
class UpperAttrMetaClass(type):
def __new__(upperattr_metaclass,future_class_name,future_class_parent,future_class_attr):
attrs = ((name,value) for name,value in future_class_attr.items() if not name.startswith('__'))
uppercase_attr = dict((name.upper(),value) for name,value in attrs)
return type.__new__(upperattr_metaclass,future_class_name,future_class_parent,uppercase_attr)
#return super(UpperAttrMetaClass,upperattr_metaclass).__new__(upperattr_metaclass,future_class_name,future_class_parent,uppercase_attr)
看起来有些负载,这些参数都是啥
我们看看type的文档
def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
# (copied from class doc)
"""
pass
type(name, bases, dict) -> a new type就是创建我们的类的方法,name是要创建的类的名字,base是要创建类的基类,dict是类的属性,正是因为有这个属性,我们才可以对类的创建自定义各种动作
通常元类用来创建API是非常好的选择,使用元类的编写很复杂但使用者可以非常简洁的调用API
著名的Django的ORM用的就是元类
class Field(object):
def __init__(self,name,column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return '<%s:%s>' % (self.__class__,self.name)
class StringField(Field):
def __init__(self,name):
super(StringField,self).__init__(name,'varchar(100)')
class IntField(Field):
def __init__(self,name):
super(IntField,self).__init__(name,'bigint')
class ModelMetaclass(type):
def __new__(cls, name, bases,attrs):
if name == 'Model':
return type.__new__(cls,name,bases,attrs)
print('Found model :%s' % name)
mapping = {}
for k,v in attrs.items():
if isinstance(v,Field):
print('Found mapping:%s ==> %s' %(k,v))
mapping[k] = v
for k in mapping.keys():
attrs.pop(k)
attrs['__mappings__'] = mapping
attrs['__table__'] = name
return type.__new__(cls,name,bases,attrs)
class Model(dict,metaclass=ModelMetaclass):
def __init__(self,**kw):
super(Model,self).__init__(**kw)
def __getattr__(self, item):
try:
return self[item]
except KeyError:
raise AttributeError('Model object ha no attribute: %s' % item)
def __setattr__(self, key, value):
self[key] = value
def save(self):
fields = []
params = []
args = []
for k,v in self.__mappings__.items():
fields.append(v.name)
params.append('?')
args.append(self[k])
#args.append(getattr(self,k,None))
sql = 'insert into %s (%s) values (%s)' %(self.__table__,','.join(fields),','.join(params))
print('SQL:%s' % sql)
print('ARGS: %s' % str(args))
class User(Model):
id = IntField('id')
name = StringField('username')
email = StringField('email')
password = StringField('pwd')
直接说可能不好理解,拿这份代码去调试一下,就什么都懂了,代码从廖雪峰网上抄的
下面再用元类来实现一个单例模式
一般我们可以用重写__new__来实现单例
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'_instance'):
cls._instance = super(Singleton,cls).__new__(cls,*args,**kwargs)
return cls._instance
s1 = Singleton()
s2 = Singleton()
print('singleton',s1 is s2)
那么用元类该如何实现
class MetaSingleton(type):
def __init__(self,*args,**kwargs):
self._instance = None
super(MetaSingleton,self).__init__(*args,**kwargs)
def __call__(self, *args, **kwargs):
if self._instance is None:
self._instance = super(MetaSingleton,self).__call__(*args,*kwargs)
return self._instance
class Singleton1(object,metaclass=MetaSingleton):
pass
s1 = Singleton1()
s2 = Singleton1()
print('singleton1',s1 is s2)
很多人可能看不懂了,为啥这里要用__init__,__call__又是干啥的,其实一开始我也被弄乱了,后来想了想就明白了,__new__是类被创建的时候执行的,注意是类创建,而不是类实例的创建,类的创建是在模块被导入的时候就创建好的,后面我们用到的其实都是类的实例,那么还记得之前我们说的元类的作用吗,它是用来创建类的,注意是类(又强调一次)不是类的实例。当我们在执行创建类实例的时候执行的是__call__的方法,正常情况是这样
class test(object):
def __init__(self):
print('init')
def __call__(self, *args, **kwargs):
print('call')
def __new__(cls, *args, **kwargs):
print('new')
return super(test,cls).__new__(cls,*args,**kwargs)
t = test()
t()
看上去有些奇怪,t是个实例,怎么能执行呢,python就是这样,如果定义了__call__就可以这样(记住这个__call__是属于这个类实例对象的),这时候我们再回去,还记得type创建的是个什么吗,它创建了一个类(它是type实例化后的对象),在我们实例化这个类的时候就会执行这个类的__call__
二、abc.ABCMeta
简单的说ABCMeta就是让你的类变成一个纯虚类,子类必须实现某个方法,这个方法在父类中用@abc.abstractmethod修饰
例如
import abc
class Base(object,metaclass=abc.ABCMeta):
@abc.abstractmethod
def func_a(self,data):
'''
:param data:
:return:
'''
@abc.abstractmethod
def func_b(self,data,out):
'''
:param data:
:param out:
:return:
'''
def func_d(self):
print('func_d in base')
你可以实现这两个虚方法,也可以不实现
这样在Base的子类中就必须实现func_a,func_b2个函数,否则就会报错
class Sub(Base):
def func_a(self,data):
print('over write func_a',data)
def func_b(self,data,out):
print('over write func_b')
如果还想调用虚类的方法用super
def func_b(self,data,out):
super(Sub,self).func_b(data,out)
print('over write func_b')
还有一种方法是,注册虚子类
class Register(object):
def func_c(self):
print('func_c in third class')
def func_a(self,data):
print('func_a in third class',data)
Base.register(Register)
这样调用issubclass(), issubinstance()进行判断时仍然返回真值(不知道这有啥用)
三、python中定义泛型方法
需要用到functools.singledispatch
#泛型方法
@functools.singledispatch
def fun(arg,verbose = False):
if verbose:
print('Let me just say:',end=' ')
print(arg)
#重载方法
@fun.register(int)
def _(arg,verbose = False):
if verbose:
print('accept int param:',end=' ')
print(arg)
fun('123',True)
fun(123,True)