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: {}