Python属性、方法和类管理系列之----元类

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

元类的介绍请看位于下面网址的一篇文章,写的相当好。

http://blog.jobbole.com/21351/

实例补充class Meta(type):

def __new__(meta, cls, parent, attr_dict):

res = super(Meta, meta).__new__(meta,cls, parent, attr_dict)PRint('meta new stage, %s is %s, %s is %s' % (meta, type(meta), cls, type(cls)))

return res

def __init__(self,cls, parent, attr_dict):

super(Meta, self).__init__(cls,parent, attr_dict)

print('meta init stage, %s is %s, %s is %s' % (self, type(self), cls, type(cls)))

def __call__(self, *args, **kargs):

print('meta call stage, %s is %s' % (self, type(self)))

return super(Meta, self).__call__(*args, **kargs)

def decorate(cls):

print('decorate cls, %s is %s' % (cls, type(cls)))

return cls

@decorate

class A(metaclass=Meta):

def __new__(cls):

res = super(A, cls).__new__(cls)

print('A new stage, %s is %s' % (cls, type(cls)))

return res

def __init__(self):

super(A, self).__init__()

print('A init stage, %s is %s' % (self, type(self)))

def test(self):

pass

a=A()

print(a)

运行结果如下:

meta new stage, <class '__main__.Meta'> is <class 'type'>, A is <class 'str'>

meta init stage, <class '__main__.A'> is <class '__main__.Meta'>, A is <class 'str'>

decorate cls, <class '__main__.A'> is <class '__main__.Meta'>

meta call stage, <class '__main__.A'> is <class '__main__.Meta'>

A new stage, <class '__main__.A'> is <class '__main__.Meta'>

A init stage, <__main__.A object at 0x00000000022A74E0> is <class '__main__.A'>

<__main__.A object at 0x00000000022A74E0>

说明:

当我们自己创建一个类时,其实Python内部的运作机制如下:

看这个类中是否有设置元类,如果有,调用该元类进行初始化,如果没有,调用type进行初始化。

无论是我们自己定义的元类还是type,都有一个__new__方法,用来生成元类, 都有一个__init__用来初始化类。

查看是否有类的装饰器,如果有的话,调用之。

其实,元类的__new__和__init__几乎什么都不做。

当我们创建一个类的实例时,其实Python内部的运作机制如下:

调用元类的__call__方法,该方法会做两件事情:

调用类自身的__new__方法用来创建类(如果有的话),如果我们没有显示的定义它,那么会调用从object继承过来的__new__方法。

调用类自身的__init__方法(如果有的话)来初始化得到实例,如果我们没有显示的定义它,那么会调用从object继承过来的__init__方法。

其实,object的__init__几乎什么都不做。应用实例由于我们经常在写类的内置拦截器方法时,少写下划线,或者出现拼写错误,从而怎么调试都不能发现问题所在,在浪费了很多时间以后才发现时犯的是多么低级的错误。

下面我写了这个元类来进行检查。

class AttrCheckMeta(type):

def __new__(meta, cls, parent, attr_dict):

import types

attrs_checking_list=['__init__', '__del__', '__call__', '__str__', '__repr__',

'__getattr__', '__setattr__', '__delattr__', '__getattribute__',

'__getitem__', '__setitem__', '__delitem__', '__iter__', '__next__',

'__contains__', '__get__', '__set__', '__delete__', '__lt__',

'__le__', '__gt__', '__ge__', '__eq__', '__add__', '__iadd__',

'__radd__', '__sub__', '__isub__', '__rsub__', '__mul__', '__imul__',

'__neg__', '__pos__', '__abs__', '__floordiv__', '__ifloordiv__',

'__truediv__', '__itruediv__', '__mod__', '__imod__', '__imod__',

'__pow__', '__ipow__', '__concat__', '__iconcat__', '__and__',

'__iand__', '__or__', '__ior__', '__xor__', '__ixor__', '__inv__',

'__invert__ ', '__lshift__', '__ilshift__', '__rshift__', '__irshift__ ',

'__bool__', '__len__', '__nonzero__', '__enter__', '__exit__',

'__new__', '__index__', '__oct__', '__hex__']

for attr,value in attr_dict.items():

#处理方法名前后都包含__,但是名字写错的情况。

if attr[:2]=='__' and attr[-2:]=='__' and isinstance(value, types.FunctionType):

if attr not in attrs_checking_list:

print('found problem function: %s' % attr)

#处理漏写后面__的情况,此时Python会把这个方法吗当成是需要扩张的方法。

elif attr.startswith('_'+cls+'__') and isinstance(value, types.FunctionType):

print('maybe has problem: %s' % attr)

return super(AttrCheckMeta, meta).__new__(meta,cls, parent, attr_dict)

def __init__(self,cls, parent, attr_dict):

super(AttrCheckMeta, self).__init__(cls,parent, attr_dict)

def __call__(self, *args, **kargs):

return super(AttrCheckMeta, self).__call__(*args, **kargs)

class A(metaclass=AttrCheckMeta):

def __new__(cls):

return super(A, cls).__new__(cls)

def __add(self, va, val):

pass

def __innit__(self):

super(A, self).__init__()

a=A()

故意写了两个错误在类A中,运行结果如下:

found problem function name: __innit__

maybe has problem: _A__add

当然,这个可以用装饰器来完成同样的任务,而且装饰器似乎更加直白、容易理解。

代码如下:

def check_ol(cls):

'''the overloading function name is easily to have spelling mistake.

It will be very hard to find the related mistakes, so i use this automethod to check

It will print the possible mistakes once found, will do nothing if passed'''

import types

attrs_checking_list=['__init__', '__del__', '__call__', '__str__', '__repr__',

'__getattr__', '__setattr__', '__delattr__', '__getattribute__',

'__getitem__', '__setitem__', '__delitem__', '__iter__', '__next__',

'__contains__', '__get__', '__set__', '__delete__', '__lt__',

'__le__', '__gt__', '__ge__', '__eq__', '__add__', '__iadd__',

'__radd__', '__sub__', '__isub__', '__rsub__', '__mul__', '__imul__',

'__neg__', '__pos__', '__abs__', '__floordiv__', '__ifloordiv__',

'__truediv__', '__itruediv__', '__mod__', '__imod__', '__imod__',

'__pow__', '__ipow__', '__concat__', '__iconcat__', '__and__',

'__iand__', '__or__', '__ior__', '__xor__', '__ixor__', '__inv__',

'__invert__ ', '__lshift__', '__ilshift__', '__rshift__', '__irshift__ ',

'__bool__', '__len__', '__nonzero__', '__enter__', '__exit__',

'__new__', '__index__', '__oct__', '__hex__']

for attr,value in cls.__dict__.items():

#处理方法名前后都包含__,但是名字写错的情况。

if attr[:2]=='__' and attr[-2:]=='__' and isinstance(value, types.FunctionType):

if attr not in attrs_checking_list:

print('found problem function name: %s' % attr)

#处理漏写后面__的情况,此时Python会把这个方法吗当成是需要扩张的方法。

elif attr.startswith('_'+cls.__name__+'__') and isinstance(value, types.FunctionType):

print('maybe has problem: %s' % attr)

return cls

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航