請看位于下面網址的一篇文章,寫的相當好。
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@decorateclass 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): passa=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內部的運作機制如下:
__new__方法,用來生成元類, 都有一個__init__用來初始化類。__new__和__init__幾乎什么都不做。__call__方法,該方法會做兩件事情:__new__方法用來創建類(如果有的話),如果我們沒有顯示的定義它,那么會調用從object繼承過來的__new__方法。__init__方法(如果有的話)來初始化得到實例,如果我們沒有顯示的定義它,那么會調用從object繼承過來的__init__方法。__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新聞熱點
疑難解答