python 元类系列 一

python 元类系列 一

定制类的作用,在生产类的时候,进行定制

增加函数调用的日志

使得生产出来的类的函数方法,能够输出一些日志信息的同时才执行

$ cat  meta2.py 
#!/usr/bin/env python
# coding=utf-8

#-*-coding:utf-8 -*-

class Logged(type):
    """A metaclass that causes classes that it creates to log  
    their function calls."""

    def __new__(cls, name, bases, attrs):
        print("Logged __new__ cls: %s, name: %s"%(cls, name))
        for key, value in attrs.items():
            print("key, value: %s, %s"%(key, value))
            if callable(value):
                attrs[key] = cls.log_call(value)
        print("Logged __new__ attrs: %s"%(attrs))

        return super(Logged, cls).__new__(cls, name, bases, attrs)

    @classmethod
    def log_call(cls, fxn):
        """
        Given a function, wrap it with some logging code and return the
        wrapped function.
        """
        def inner(*args, **kwargs):
            print('The function %s was called with arguments %r and keyword arguments %r.' \
                  % (fxn.__name__, args, kwargs))

            try:
                response = fxn(*args, **kwargs)
                print ('The function call to %s was successful.' % fxn.__name__)
                return response
            except Exception as exc:
                print ('The function call to %s raised an exception: %r' % (fxn.__name__, exc))
                raise

        return inner


class Myclass(object):
    __metaclass__ = Logged
    def foo(self):
        print("exec foo")

    def bar(self):
        raise TypeError('oh noes!')

if __name__ == '__main__':
    obj = Myclass()
    obj.foo()

能看到函数,全部被代理了

$ python2   -i meta2.py
Logged __new__ cls: <class '__main__.Logged'>, name: Myclass
key, value: bar, <function bar at 0x7fb795759938>
key, value: __module__, __main__
key, value: foo, <function foo at 0x7fb7957598c0>
key, value: __metaclass__, <class '__main__.Logged'>
Logged __new__ attrs: {'bar': <function inner at 0x7fb795759668>, '__module__': '__main__', 'foo': <function inner at 0x7fb7957599b0>, '__metaclass__': <function inner at 0x7fb795759a28>}
The function foo was called with arguments (<__main__.Myclass object at 0x7fb795770190>,) and keyword arguments {}.
exec foo
The function call to foo was successful.
>>> Myclass.__dict__
dict_proxy({'__module__': '__main__', '__metaclass__': <function inner at 0x7fb795759a28>, '__dict__': <attribute '__dict__' of 'Myclass' objects>, 'bar': <function inner at 0x7fb795759668>, 'foo': <function inner at 0x7fb7957599b0>, '__weakref__': <attribute '__weakref__' of 'Myclass' objects>, '__doc__': None})

函数大写也能调用

#!/usr/bin/env python
# coding=utf-8

#-*-coding:utf-8 -*-

class Logged(type):
    """A metaclass that causes classes that it creates to log  
    their function calls."""

    def __new__(cls, name, bases, attrs):
        print("Logged __new__ cls: %s, name: %s"%(cls, name))
        for key, value in attrs.items():
            print("key, value: %s, %s"%(key, value))
            key = key.upper()
            if callable(value):
                attrs[key] = cls.log_call(value)
        print("Logged __new__ attrs: %s"%(attrs))

        return super(Logged, cls).__new__(cls, name, bases, attrs)

    @classmethod
    def log_call(cls, fxn):
        """
        Given a function, wrap it with some logging code and return the
        wrapped function.
        """
        def inner(*args, **kwargs):
            print('The function %s was called with arguments %r and keyword arguments %r.' \
                  % (fxn.__name__, args, kwargs))

            try:
                response = fxn(*args, **kwargs)
                print ('The function call to %s was successful.' % fxn.__name__)
                return response
            except Exception as exc:
                print ('The function call to %s raised an exception: %r' % (fxn.__name__, exc))
                raise

        return inner


class Myclass(object):
    __metaclass__ = Logged
    def foo(self):
        print("exec foo")

    def bar(self):
        raise TypeError('oh noes!')

if __name__ == '__main__':
    obj = Myclass()
    obj.foo()

能看到类的属性里面增加了 名字为大写的函数方法

$ python2 -i   meta3.py
Logged __new__ cls: <class '__main__.Logged'>, name: Myclass
key, value: bar, <function bar at 0x7f95b3df8938>
key, value: __module__, __main__
key, value: foo, <function foo at 0x7f95b3df88c0>
key, value: __metaclass__, <class '__main__.Logged'>
Logged __new__ attrs: {'__module__': '__main__', 'FOO': <function inner at 0x7f95b3df89b0>, 'bar': <function bar at 0x7f95b3df8938>, 'BAR': <function inner at 0x7f95b3df8668>, '__metaclass__': <class '__main__.Logged'>, 'foo': <function foo at 0x7f95b3df88c0>, '__METACLASS__': <function inner at 0x7f95b3df8a28>}
exec foo
>>> obj.FOO()
The function foo was called with arguments (<__main__.Myclass object at 0x7f95b3d90290>,) and keyword arguments {}.
exec foo
The function call to foo was successful.

demo1

#!/usr/bin/env python
# coding=utf-8
class MyType(type):
    # 自定义一个type的派生类
    #type(cls_name,bases,  attrs) ===>args as follow
    def __init__(self,*args,**kwargs):
        print('xx self: %s, args: %s, kwargs: %s'%(self, args, kwargs))
        super(MyType,self).__init__(*args,**kwargs)
        print("__init__ end")

    def __call__(cls, *args, **kwargs):
        print("__call__ cls: %s"%cls)
        obj = cls.__new__(cls,*args, **kwargs)
        print("__call__ obj: %s"%obj) 
        cls.__init__(obj,*args, **kwargs)
        print("__call__ args: %s, kwargs: %s"%(args, kwargs))
        return obj

def with_metaclass(base):
    return MyType("MyType2",(base,),{})

# 方式一
class Foo(metaclass=MyType):
    # metaclass=MyType,即指定了由MyType创建Foo类,当程序运行,用到class Foo时,即调用MyType的__init__方法,创建Foo类
    def __init__(self,name):
        print("Foo __init__ name: %s"%name)
        self.name = name
        print("Foo __init__ end")
    def test1(self):
        #Foo equal MyType instanial, so Foo(2) will call the __call__
        Foo(2)


#方式二    在Flask的wtform的源码中用到过
# class Foo(with_metaclass(object)):
#     def __init__(self,name):
#         self.name = name


#a=Foo('name')
$ python3  -i meta1.py
xx self: <class '__main__.Foo'>, args: ('Foo', (), {'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x7f0bb9e41840>, 'test1': <function Foo.test1 at 0x7f0bb9e418c8>}), kwargs: {}
__init__ end
>>> a = Foo('zzz')
__call__ cls: <class '__main__.Foo'>
__call__ obj: <__main__.Foo object at 0x7f0bb9f0c748>
Foo __init__ name: zzz
Foo __init__ end
__call__ args: ('zzz',), kwargs: {}
>>> a.test1
<bound method Foo.test1 of <__main__.Foo object at 0x7f0bb9f0c748>>
>>> a.test1()
__call__ cls: <class '__main__.Foo'>
__call__ obj: <__main__.Foo object at 0x7f0bb9f0ca20>
Foo __init__ name: 2
Foo __init__ end
__call__ args: (2,), kwargs: {}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值