2012-01-13 35 views
7

Trong C/C++, tôi thường thấy hữu ích khi gỡ lỗi để xác định macro, ví dụ ECHO(x), in tên biến và giá trị của nó (ví dụ: ECHO(variable) in variable 7). Bạn có thể lấy tên biến trong macro bằng cách sử dụng toán tử 'stringification' # như được mô tả here. Có cách nào để làm điều này trong Python?Tìm tên của biến số Python được chuyển đến hàm

Nói cách khác, tôi muốn có một chức năng

def echo(x): 
    #magic goes here 

đó, nếu gọi là foo=7; echo(foo) (hoặc foo=7; echo('foo'), có lẽ), sẽ in ra foo 7. Tôi nhận ra nó là tầm thường để làm điều này nếu tôi chuyển cả biến và tên của nó cho hàm, nhưng tôi sử dụng các hàm như thế này rất nhiều trong khi gỡ lỗi, và sự lặp lại luôn luôn làm tôi khó chịu.

Trả lời

7

Không thực sự giải pháp, nhưng có thể có ích (anyway bạn có echo('foo') trong câu hỏi):

def echo(**kwargs): 
    for name, value in kwargs.items(): 
     print name, value 

foo = 7 
echo(foo=foo) 

UPDATE: Giải pháp cho echo(foo) với inspect

import inspect 
import re 

def echo(arg): 
    frame = inspect.currentframe() 
    try: 
     context = inspect.getframeinfo(frame.f_back).code_context 
     caller_lines = ''.join([line.strip() for line in context]) 
     m = re.search(r'echo\s*\((.+?)\)$', caller_lines) 
     if m: 
      caller_lines = m.group(1) 
     print caller_lines, arg 
    finally: 
     del frame 

foo = 7 
bar = 3 
baz = 11 
echo(foo) 
echo(foo + bar) 
echo((foo + bar)*baz/(bar+foo)) 

Output:

foo 7 
foo + bar 10 
(foo + bar)*baz/(bar+foo) 11 

Cuộc gọi có cuộc gọi nhỏ nhất nhưng nhạy cảm với các dòng mới, ví dụ::

echo((foo + bar)* 
     baz/(bar+foo)) 

Sẽ in:

baz/(bar+foo)) 11 
+0

Đó giải pháp thứ hai là cực kỳ thông minh. Trong khi tìm hiểu cách hoạt động, tôi đã tìm thấy một câu hỏi trùng lặp [ở đây] (http://stackoverflow.com/questions/5503363/can-you-translate-this-debugging-macro-from-c-to-python) - mặc dù regex của bạn mạnh hơn một chút so với câu trả lời tương tự ở đó. – James

+0

câu trả lời tuyệt vời, cảm ơn. bạn có thể giải thích ngắn gọn về cách thức hoạt động của regex? – Ferguzz

+0

@Ferguzz, Nó tìm kiếm 'echo', sau đó' \ s * '- 0 hoặc nhiều dấu cách,' \ ('- dấu ngoặc đơn,' (. +?) \) $ '- tìm kiếm không phải greddy cho tất cả các ký hiệu trước' \) '(dấu ngoặc đơn) ở cuối dòng (' $ '). Thông tin thêm tại http://www.regular-expressions.info/repeat.html. Bạn cũng có thể [gỡ lỗi regexps] (http://stackoverflow.com/a/143636/1052325). Hãy thử trong phiên Python tương tác: 're.compile (r'echo \ s * \ ((. +?) \) $ ', Re.DEBUG)' – reclosedev

3
def echo(x): 
    import inspect 
    print "{0}: {1}".format(x, inspect.stack()[1][0].f_locals[x]) 
y = 123 
echo('y') 
# 'y: 123' 

Xem thêm: https://stackoverflow.com/a/2387854/16361

Lưu ý rằng điều này có thể gây ra các vấn đề GC:

http://docs.python.org/library/inspect.html#the-interpreter-stack

Nó cũng sẽ tắt những người đã bị đốt cháy bởi rối tung với khung hình, và có thể để lại một hương vị xấu trong miệng của bạn. Nhưng nó sẽ hoạt động.

3

Đây là giải pháp mà bạn đã nhập thêm một chút để gọi nó. Nó dựa trên locals chức năng built-in:

def print_key(dictionary, key): 
    print key, '=', dictionary[key] 


foo = 7 
print_key(locals(), 'foo') 

Một echo với ngữ nghĩa mà bạn đề cập cũng có thể, sử dụng các mô-đun inspect. Tuy nhiên, hãy đọc các cảnh báo trong tài liệu của kiểm tra. Đây là một hack không di động xấu xí (nó không hoạt động trong mọi triển khai Python). Hãy chắc chắn chỉ sử dụng nó để gỡ lỗi.

Ý tưởng là xem xét locals của chức năng gọi. Mô-đun kiểm tra chỉ cho phép: các cuộc gọi được đại diện bởi các đối tượng khung được liên kết với nhau bởi thuộc tính f_back. Các biến cục bộ và toàn cục của mỗi khung có sẵn (cũng có các nội trang dựng sẵn, nhưng bạn không cần phải in chúng).

Bạn có thể xóa một cách rõ ràng bất kỳ đối tượng khung tham chiếu nào để tránh các chu kỳ tham chiếu, như được giải thích trong inspect docs, nhưng điều này là không cần thiết - bộ sưu tập rác sẽ giải phóng chúng sớm hay muộn.

import inspect 

def echo(varname): 
    caller = inspect.currentframe().f_back 
    try: 
     value = caller.f_locals[varname] 
    except KeyError: 
     value = caller.f_globals[varname] 
    print varname, '=', value 
    del caller 

foo = 7 
echo('foo') 
Các vấn đề liên quan