我正试着写一个装饰来做日志:
def logger(myFunc):
def new(*args, **keyargs):
print 'Entering %s.%s' % (myFunc.im_class.__name__, myFunc.__name__)
return myFunc(*args, **keyargs)
return new
class C(object):
@logger
def f():
pass
C().f()
我想打印:
Entering C.f
但是我得到了一条错误信息:
AttributeError: 'function' object has no attribute 'im_class'
可能这与logger中的myFunc的作用域有关,但我不知道是什么。
函数只在运行时成为方法。也就是说,当得到
C.f
时,得到一个绑定函数(和C.f.im_class is C
)。在定义函数时,它只是一个普通函数,没有绑定到任何类。这个未绑定和解除关联的函数是由logger修饰的。self.__class__.__name__
将为您提供类的名称,但您也可以使用描述符以更通用的方式完成此任务。这个模式被描述为in a blog post on Decorators and Descriptors,特别是logger decorator的实现如下所示:显然,输出可以改进(例如,通过使用
getattr(self.func, 'im_class', None)
),但是这种通用模式对方法和函数都有效。不过,它将不适用于旧式类(但不要使用那些;)克劳迪乌的答案是正确的,但是您也可以通过从
self
参数中删除类名来作弊。这会在继承的情况下给出误导性的日志语句,但会告诉您正在调用其方法的对象的类。例如:如我所说,如果您从父类继承了一个函数,那么这将无法正常工作;在这种情况下,您可能会说
然后获取消息
Entering B.f
,在这里您实际上想要获取消息Entering C.f
,因为这是正确的类。另一方面,这可能是可以接受的,在这种情况下,我建议采用这种方法而不是克劳迪乌的建议。这里提出的想法很好,但也有一些缺点:
inspect.getouterframes
和args[0].__class__.__name__
不适用于纯函数和静态方法。__get__
必须在被@wraps
拒绝的类中。@wraps
本身应该更好地隐藏痕迹。所以,我把这个页面上的一些想法、链接、文档和我自己的头脑结合起来,
最后找到了一个解决方案,它没有上述三个缺点。
因此,
method_decorator
:functools.wraps()
更正确地回答系统属性来隐藏装饰跟踪。用法:
见full unit-tests for usage details。
这里是
method_decorator
类的代码:相关问题 更多 >
编程相关推荐