关于日志记录:用Python记录方法调用的更好方法?

Better way to log method calls in Python?

我们可以将某种日志装饰器编码为echo函数/方法调用,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def log(fn):
    ...

@log
def foo():
    ...

class Foo(object):
    @log
    def foo(self):
        ...

    @log
    def bar(self, a, b):
        ...

    @log
    def foobar(self, x, y, z):
        ...

但是,如果我们想记录方法调用而不在每个方法定义前面放置那么多@log呢?有什么方法可以将一个decorator放在类定义之上,使其所有方法调用都被修饰/记录?还是有其他更好有趣的方法来代替装饰?


这可能是杀伤力过大,但有一个跟踪功能工具可以通知您程序中的大量活动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import sys

def trace(frame, event, arg):
    if event =="call":
        filename = frame.f_code.co_filename
        if filename =="path/to/myfile.py":
            lineno = frame.f_lineno
            # Here I'm printing the file and line number,
            # but you can examine the frame, locals, etc too.
            print"%s @ %s" % (filename, lineno)
    return trace

sys.settrace(trace)
call_my_function()
sys.settrace(None)

我不确定您的用例是什么,但是一般来说,我会更多地考虑您正试图解决的问题到底是什么。

也就是说,这里有一个例子,可以做你想做的,但没有装饰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python
import inspect


class Foo(object):

    def foo(self):
        pass

    def bar(self, a, b):
        pass

    def foobar(self, x, y, z):
        pass

    def __getattribute__(self, name):
        returned = object.__getattribute__(self, name)
        if inspect.isfunction(returned) or inspect.ismethod(returned):
            print 'called ', returned.__name__
        return returned


if __name__ == '__main__':
    a = Foo()
    a.foo()
    a.bar(1, 2)
    a.foobar(1, 2, 3)

输出:

1
2
3
called  foo
called  bar
called  foobar


请参见将decorator附加到类中的所有函数

然而,正如对这个问题公认的答案所指出的,这通常不是一个好主意。

如果您决定采用面向方面的编程路线,我建议从这里开始:有针对Python的AOP支持库吗?


如果您不想显式地修饰所有的函数,那么您可以获取给定模块的所有函数/方法,并自动应用修饰器。不是最简单的事情,但在python中不可行:)

您还可以尝试使用面向方面的编程框架。

MY2C