2012-03-30 6 views
5

Trong một số trường hợp, tôi muốn in kết xuất debug kiểu như thế này:tên In biến được truyền cho một hàm

# module test.py 
def f() 
    a = 5 
    b = 8 
    debug(a, b) # line 18 

Tôi muốn debug chức năng in như sau:

debug info at test.py: 18 
function f 
a = 5 
b = 8 

Tôi nghĩ rằng nó nên có thể bằng cách sử dụng mô-đun kiểm tra để xác định vị trí khung stack, sau đó tìm dòng thích hợp, tìm kiếm mã nguồn trong dòng đó, nhận được tên của các đối số từ đó. Tên hàm có thể thu được bằng cách di chuyển một khung ngăn xếp lên. (Các giá trị của các đối số dễ lấy: chúng được chuyển trực tiếp đến hàm debug.)

Tôi có đi đúng hướng không? Có công thức nào tôi có thể tham khảo?

Trả lời

3

Bạn có thể làm một cái gì đó dọc theo dòng sau đây:

import inspect 

def debug(**kwargs): 
    st = inspect.stack()[1] 
    print '%s:%d %s()' % (st[1], st[2], st[3]) 
    for k, v in kwargs.items(): 
    print '%s = %s' % (k, v) 

def f(): 
    a = 5 
    b = 8 
    debug(a=a, b=b) # line 12 

f() 

này in ra:

test.py:12 f() 
a = 5 
b = 8 
+1

Thật tuyệt vời và đơn giản! Nhưng tôi sẽ không nhớ phức tạp hơn nếu nó có nghĩa là tôi không phải lặp lại mỗi tên biến hai lần: một lần là tên arg từ khóa, và một lần là giá trị đối số từ khóa. – max

+0

Bạn có thể thử gọi 'debug (** locals())'. –

1

Bạn đang thường làm điều đó đúng, mặc dù nó sẽ dễ dàng hơn để sử dụng AOP cho loại này nhiệm vụ. Về cơ bản, thay vì gọi "gỡ lỗi" mỗi lần với mọi biến, bạn chỉ có thể trang trí mã với các khía cạnh làm những điều nhất định khi có các sự kiện nhất định, như khi nhập hàm để in các biến được truyền và tên của nó.

Vui lòng tham khảo this trang web và cũ để post để biết thêm thông tin.

1

Vâng, bạn đang đi đúng hướng. Bạn có thể muốn xem inspect.getargspec sẽ trả về một bộ tên có tên là args, varargs, keywords, mặc định được truyền cho hàm.

import inspect 

def f(): 
    a = 5 
    b = 8 
    debug(a, b) 


def debug(a, b): 
    print inspect.getargspec(debug) 
f() 
0

Điều này thực sự phức tạp. Hãy để tôi thử và đưa ra một câu trả lời hoàn chỉnh hơn, sử dụng lại this code và gợi ý về số getargspec trong câu trả lời của Senthil đã khiến tôi kích hoạt bằng cách nào đó. Thay vào đó, Btw, getargspec không được dùng trong Python 3.0 và getfullarcspec should be used.

này làm việc cho tôi trên Python 3.1.2 cả với gọi một cách rõ ràng chức năng debug và với việc sử dụng một trang trí:

# from: https://stackoverflow.com/a/4493322/923794 
def getfunc(func=None, uplevel=0): 
    """Return tuple of information about a function 

    Go's up in the call stack to uplevel+1 and returns information 
    about the function found. 

    The tuple contains 
     name of function, function object, it's frame object, 
     filename and line number""" 
    from inspect import currentframe, getouterframes, getframeinfo 
    #for (level, frame) in enumerate(getouterframes(currentframe())): 
    # print(str(level) + ' frame: ' + str(frame)) 
    caller = getouterframes(currentframe())[1+uplevel] 
    # caller is tuple of: 
    # frame object, filename, line number, function 
    # name, a list of lines of context, and index within the context 
    func_name = caller[3] 
    frame = caller[0] 
    from pprint import pprint 
    if func: 
     func_name = func.__name__ 
    else: 
     func = frame.f_locals.get(func_name, frame.f_globals.get(func_name)) 
    return (func_name, func, frame, caller[1], caller[2]) 


def debug_prt_func_args(f=None): 
    """Print function name and argument with their values""" 
    from inspect import getargvalues, getfullargspec 
    (func_name, func, frame, file, line) = getfunc(func=f, uplevel=1) 
    argspec = getfullargspec(func) 
    #print(argspec) 
    argvals = getargvalues(frame) 
    print("debug info at " + file + ': ' + str(line)) 
    print(func_name + ':' + str(argvals)) ## reformat to pretty print arg values here 
    return func_name 



def df_dbg_prt_func_args(f): 
    """Decorator: dpg_prt_func_args - Prints function name and arguments 

    """ 
    def wrapped(*args, **kwargs): 
     debug_prt_func_args(f) 
     return f(*args, **kwargs) 
    return wrapped 

Cách sử dụng:

@df_dbg_prt_func_args 
def leaf_decor(*args, **kwargs): 
    """Leaf level, simple function""" 
    print("in leaf") 


def leaf_explicit(*args, **kwargs): 
    """Leaf level, simple function""" 
    debug_prt_func_args() 
    print("in leaf") 


def complex(): 
    """A complex function""" 
    print("start complex") 
    leaf_decor(3,4) 
    print("middle complex") 
    leaf_explicit(12,45) 
    print("end complex") 


complex() 

và in:

start complex 
debug info at debug.py: 54 
leaf_decor:ArgInfo(args=[], varargs='args', keywords='kwargs', locals={'args': (3, 4), 'f': <function leaf_decor at 0x2aaaac048d98>, 'kwargs': {}}) 
in leaf 
middle complex 
debug info at debug.py: 67 
leaf_explicit:ArgInfo(args=[], varargs='args', keywords='kwargs', locals={'args': (12, 45), 'kwargs': {}}) 
in leaf 
end complex 

Trình trang trí cheats một chút: Vì trong số wrapped chúng tôi nhận được cùng một rguments là chức năng chính nó nó không quan trọng mà chúng tôi tìm thấy và báo cáo ArgSpec của wrapped trong getfuncdebug_prt_func_args. Mã này có thể được làm đẹp một chút, nhưng nó hoạt động ngay bây giờ cho các testcases gỡ lỗi đơn giản mà tôi đã sử dụng. Bạn có thể thấy rằng inspect có thể cung cấp cho bạn "ngữ cảnh" thực sự là dòng mã nguồn mà một hàm được gọi.Mã này rõ ràng không hiển thị nội dung của bất kỳ biến nào được gán cho hàm của bạn, nhưng đôi khi nó đã giúp biết tên biến được sử dụng một cấp ở trên hàm được gọi của bạn.

Như bạn thấy, với trình trang trí, bạn không phải thay đổi mã bên trong hàm.

Có thể bạn sẽ muốn in đẹp các arg. Tôi đã để lại bản in thô (và cũng là một nhận xét in ra nhận xét) trong chức năng vì vậy nó dễ dàng hơn để chơi xung quanh với.