有没有比使用装饰器记录函数输出而不编辑它更好的方法?

时间:2015-03-16 05:01:17

标签: python python-decorators

好。所以,我的问题可能有点模糊。这就是我想要做的事情:

我已经继承了'大量的python脚本,我应该调试,记录和改进它们。目前还没有很多文档可供使用。在几乎所有情况下,我都知道输入数据和输出数据需要什么。

我的计划是将原始函数包装在装饰器函数周围,并将输出记录在文本文件中,同时不中断正常的程序流程。我也不想暂时搞乱原始源代码。所以,这是装饰器的代码:

def printoutput(func):
"""Decorator function to write the values of a function to a log file
    1. If the output is a tuple or a list then the output will get written as Output1: .. , Output2:.. etc.
    2. If the output is anything else, it will get written once.
"""

import time

#Accesfunc passes arguments to a calls the actual function. It also logs data.
 def accessfunc(*args,**kwargs):
    #Call the function with any number of arguments and keyword arguments.
    y = func(*args,**kwargs) 

    #Save the name of the function being called.
    funcname = r"D:\{}_{}_output.txt".format(time.time(), func.__name__)

    #Create a file for logging data, specific to a function.
    with open(funcname,'w') as fileoutput:

        #if the output returned by the function is a lsit or tuple then log those on separate lines.
        if isinstance(y,(tuple,list)):
            for idx,outputs in enumerate(y):
                fileoutput.write("Output{}:".format(idx))
                fileoutput.write(str(outputs)+"\n")

        #if the output is a single entity like a string or a number then log it on a single line.
        else:
                fileoutput.write("Output:\n")
                fileoutput.write(str(y))
    return y
 return accessfunc

我的问题是:

  1. 有没有更好的方法来完成我想要做的事情?

  2. 我正在记录函数的名称,有没有办法我也可以记录返回的变量的名称。例如,如果函数A返回B,我可以以这样的方式记录它,即" A"和" B"在我的日志文件中提到?

2 个答案:

答案 0 :(得分:1)

sys.settrace可以向您显示很多内容而无需修改任何内容。

http://pymotw.com/2/sys/tracing.html

这是对其中一个示例的略微修改,它们在执行函数之前从堆栈帧中抓取局部变量,其中包含参数。

import sys

def trace_calls_and_returns(frame, event, arg):
    co = frame.f_code
    func_name = co.co_name
    if func_name == 'write':
        # Ignore write() calls from print statements
        return
    line_no = frame.f_lineno
    filename = co.co_filename
    if event == 'call':
        print 'Call to %s(%s) on line %s of %s' % (func_name, frame.f_locals, line_no, filename)
        return trace_calls_and_returns
    elif event == 'return':
        print '%s() => %s' % (func_name, arg)
    return

def times(a,b):
    foo = "what"
    return a*b

def x(a):
    return times(a,a)

def y(a):
    return times(a,2)

sys.settrace(trace_calls_and_returns)
foo=x(x(y(x(2))))

输出:

Call to x({'a': 2}) on line 24 of C:/Users/cjd/Desktop/dfdfdfdf.py
Call to times({'a': 2, 'b': 2}) on line 20 of C:/Users/cjd/Desktop/dfdfdfdf.py
times() => 4
x() => 4
Call to y({'a': 4}) on line 27 of C:/Users/cjd/Desktop/dfdfdfdf.py
Call to times({'a': 4, 'b': 2}) on line 20 of C:/Users/cjd/Desktop/dfdfdfdf.py
times() => 8
y() => 8
Call to x({'a': 8}) on line 24 of C:/Users/cjd/Desktop/dfdfdfdf.py
Call to times({'a': 8, 'b': 8}) on line 20 of C:/Users/cjd/Desktop/dfdfdfdf.py
times() => 64
x() => 64
Call to x({'a': 64}) on line 24 of C:/Users/cjd/Desktop/dfdfdfdf.py
Call to times({'a': 64, 'b': 64}) on line 20 of C:/Users/cjd/Desktop/dfdfdfdf.py
times() => 4096
x() => 4096
Call to flush_stdout({}) on line 219 of C:\Python27\lib\idlelib\run.py
flush_stdout() => None
Call to put({'item': (119, None), 'self': <Queue.Queue instance at 0x0000000002B42AC8>, 'block': True, 'timeout': None}) on line 107 of C:\Python27\lib\Queue.py
Call to _put({'item': (119, None), 'self': <Queue.Queue instance at 0x0000000002B42AC8>}) on line 204 of C:\Python27\lib\Queue.py

答案 1 :(得分:0)

在我的情况下,装饰器用于缓存或方便。

对于日志记录,python的内置日志记录非常方便。

  1. 配置记录

    logging.config.dictConfig(config.LOGGING)
    

    config.LOGGING类似于: Python Logging Config

  2. 使用记录

    import logging
    
    logger = logging.getLogger(__name__)
    
    logger.info('This is a info log.')
    
  3. 在我看来,日志应该存在于你的代码中,它是一种记录,它应该是明确的,如Python-Zen所说。因此,我不建议装饰人员进行伐木。