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


    元类的介绍

    请看位于下面网址的一篇文章,写的相当好。
    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内部的运作机制如下:

    1. 看这个类中是否有设置元类,如果有,调用该元类进行初始化,如果没有,调用type进行初始化。
    2. 无论是我们自己定义的元类还是type,都有一个__new__方法,用来生成元类, 都有一个__init__用来初始化类。
    3. 查看是否有类的装饰器,如果有的话,调用之。
      其实,元类的__new____init__几乎什么都不做。
      当我们创建一个类的实例时,其实Python内部的运作机制如下:
    4. 调用元类的__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
    
    
  • 相关阅读:
    一个很好的国外的算法网站
    Windows 2008 R2 强制删除Cluster
    .net 4.5 新特性 async await 一般处理程序实例
    基于RSA的加密/解密示例C#代码
    解决WCF 调用方未由服务器进行身份验证或消息包含无效或过期的安全上下文令牌
    SQL Server查看所有表大小,所占空间
    关于Latch
    关闭SQL Server 数据库所有使用连接
    MysqliDb 库的一些使用简单技巧(php)
    Linux 常用命令
  • 原文地址:https://www.cnblogs.com/jessonluo/p/4760059.html
Copyright © 2020-2023  润新知