参考链接:Python基础:元类 - RussellLuo - 博客园 (cnblogs.com),oop - What are metaclasses in Python? - Stack Overflow,
元类(metaclass)是Python 2.2中引入的概念,利用元类可以 定制类的创建行为(Customizing class creation),是定义类的类。
1、类的创建过程
对于类定义:class Foo(Base): def say(self): print 'hello'
- 确定元类
mcls
。元类的查找优先级为:- 首先查找类Foo是否拥有属性
__metaclass__
- 否则查找类Foo的父类是否具有属性
__metaclass__
- 否则查找类Foo所在模块是否具有全局变量
__metaclass__
- 否则使用默认元类(经典类:
types.ClassType
;新式类:type
)
- 首先查找类Foo是否拥有属性
- 使用元类
mcls
创建类Foo
。创建语意等价于:# 元类的初始化参数:mcls(name, bases, dict)
# 其中,name是待生成类的名字,bases是所有父类的列表,dict是待生成类的所有属性对应的字典 Foo = mcls('Foo', (Base,), {'say': say}) - 创建成功后,类
Foo
是元类mcls
的实例。
# 创建类: # 类: mcls # 实例:Foo class Foo: pass # 等价于 Foo = mcls('Foo', (), {}) # 创建类的实例 # 类: Foo # 实例:fooObj foo = Foo()
2、元类的使用惯例
原则上,元类可以是:任何接受参数name,bases,dict并返回类的可调用对象(类或函数,参考metaclass)。其中,- name:待创建类的名字
- bases:待创建类的父类(注意,不包含更深的祖先类)
- dict:待创建类的所有attributes的名字和handle
def metacls_func(name, bases, dict): # do customizing here return type(name, bases, dict)
class MetaCls(type): def __new__(cls, name, bases, dict): # do customizing here: 下面语句对应使用默认的元类type生成类(cls实际上是MetaCls的self) return super(MetaCls, cls).__new__(cls, name, bases, dict)
注意:
-
元类可以继承自另一个元类,也可以使用其他元类
-
除了常用的
__new__
,还可以借助__init__
和__call__
来定制被创建的类
3、案例
默认类生成行为
以新式类(New-style classes)为例:类New
的三种等价定义class New(object): pass class New: __metaclass__ = type New = type('New', (), {})
类New
是元类type
的实例:
>>> isinstance(New, type)
True
使用元类
为所有类打上作者标签:class AuthorTag(type): def __new__(cls, name, bases, dict): dict['__author__'] = 'RussellLuo' return super(AuthorTag, cls).__new__(cls, name, bases, dict) class MyBlog: __metaclass__ = AuthorTag class MyGitHub: __metaclass__ = AuthorTag
MyBlog
和类MyGitHub
都获得了作者签名:
>>> MyBlog.__author__ 'RussellLuo' >>> MyGitHub.__author__ 'RussellLuo'
使用metacalss的方式有多种,具体列举如下几种:
# python 2 class MyBlog: __metaclass__ = AuthorTag # python 3 class MyBlog(metaclass = AuthorTag): pass # both python 2 & 3 import six @six.add_metaclass(Meta) class MyBlog(object): pass
进阶案例
下面的案例,利用metaclass实现了为类的所有attribute function批量添加wrapper函数的功能(参考原链接python3利用元类批量给所有继承类增加装饰器_这天鹅肉有毒-CSDNimport six
import types import inspect from functools import wraps from collections import OrderedDict def xx(func): @wraps(func) def wrap(*args,**kwargs): print('*'*150) print('执行了decorator') res=func(*args,**kwargs) if res: return res print('执行完毕') print('*'*150) return wrap class Meta(type): @classmethod def options(cls,bases,attrs): def _add_wrapper(value, key): if hasattr(value,'__func__') or isinstance(value,types.FunctionType): if isinstance(value,staticmethod): return staticmethod(cls.func(value.__func__)) elif isinstance(value,classmethod): return classmethod(cls.func(value.__func__)) elif isinstance(value, property): return property(fget=cls.func(value.fget), fset=cls.func(value.fset), fdel=cls.func(value.fdel),doc=value.__doc__) elif not key.startswith('__') : return cls.func(value) return value new_attrs=OrderedDict() #循环自己的所有属性 for key,value in attrs.items(): #对各种类型的方法进行分别处理 new_attrs[key]=_add_wrapper(value, key) # 循环所有父类 for base in bases: for key,value in base.__dict__.items(): if key not in new_attrs: new_attrs[key]=_add_wrapper(value, key) return new_attrs def __new__(cls, name, bases, attrs): cls.func=attrs.get('meta_decoator') assert inspect.isfunction(cls.func), ('传入的meta装饰器不正确') #在类生成的时候添加wrapper new_attrs = cls.options(bases, attrs) return super().__new__(cls,name,bases, new_attrs) class obj(object): def __init__(self): print('obj.__init__') @classmethod def one(self): print('obj.one') @six.add_metaclass(Meta) class obj1(obj): #只要继承类中有meta_decoator属性,这个属性的方法就会自动装饰下面所有的方法 #包括类属性,实例属性,property属性,静态属性 meta_decoator=xx aa=1 @classmethod def three(cls): print('obj1.three') @staticmethod def four(): print('obj1.four') def two(self): print(self.pro) print('obj1.two') @property def pro(self): return 1
完结,撒花~