python中面向方面的技术?

Ste*_*oss 4 python

所以我在Python中有一个有趣的问题,可以通过面向方面的技术来解决.情况如下:

  1. 我有一堆模块,每个模块都有一堆功能.
  2. 我有一个可执行文件调用这些模块中的一些函数集.
  3. 当可执行文件调用其中一个函数时,我想要一个使用函数调用的详细信息生成的日志语句(名称和参数)
  4. 当其中一个模块调用其他模块的一个函数时,我不希望生成任何日志语句.

有没有方便的方法在Python中执行此操作,而不会在每个模块的函数中粘贴日志语句?

unu*_*tbu 5

修改可执行文件中函数的行为可以使用装饰器完成:

#!/usr/bin/env python
from module1 import foo
from module2 import bar

def trace(f):
    def tracewrapper(*arg, **kw):
        arg_str=','.join(['%r'%a for a in arg]+['%s=%s'%(key,kw[key]) for key in kw])
        print "%s(%s)" % (f.__name__, arg_str)
        return f(*arg, **kw)
    return tracewrapper

verbose_functions=[foo,bar]  # add whatever functions you want logged here
for func in verbose_functions:
    globals()[func.func_name]=trace(func)
Run Code Online (Sandbox Code Playgroud)

由于您只修改了可执行文件命名空间中函数的定义,因此模块的功能保持不变.当一个模块的函数调用另一个模块的函数时,它会被跟踪修改,并且不会生成任何日志语句.

如果你只想直接来自main()来记录函数调用,那么你可以使用这样的跟踪装饰器:

import traceback
def trace(f,filename,funcname):
    def tracewrapper(*arg, **kw):
        stacks=traceback.extract_stack()
        (s_filename,s_lineno,s_funcname,s_text)=stacks[-2]
        # Alternatively, you can search the entire call stack
        # for (s_filename,s_lineno,s_funcname,s_text) in stacks:
        if s_filename.endswith(filename) and s_funcname==funcname: 
            arg_str=','.join(['%r'%a for a in arg]+
                             ['%s=%s'%(key,kw[key]) for key in kw])
            print "%s(%s)" % (f.__name__, arg_str)                
        return f(*arg, **kw)
    return tracewrapper
verbose_functions=[foo,bar]  # add whatever functions you want logged here
for func in verbose_functions:
    # You can pass the module's filename and the function name here
    globals()[func.func_name]=trace(func,'test.py','main')
Run Code Online (Sandbox Code Playgroud)

请注意,使用上面的跟踪

def baz():
    foo(3,4)
def main():
    foo(1,2,'Hi')
    bar(x=3)
    baz()
Run Code Online (Sandbox Code Playgroud)

会记录foo(1,2,'Hi')和bar(x=3)调用,但不是 foo(3,4)因为这个调用不直接来自main.但是,它主要来自main,因为主要调用baz.如果您想记录foo(3,4)呼叫,那么您需要遍历整个堆栈:

import traceback
def trace(f,filename,funcname):
    def tracewrapper(*arg, **kw):
        stacks=traceback.extract_stack()        
        for (s_filename,s_lineno,s_funcname,s_text) in stacks:
            if s_filename.endswith(filename) and s_funcname==funcname: 
                arg_str=','.join(['%r'%a for a in arg]+
                                 ['%s=%s'%(key,kw[key]) for key in kw])
                print "%s(%s)" % (f.__name__, arg_str)                
        return f(*arg, **kw)
    return tracewrapper
Run Code Online (Sandbox Code Playgroud)