2011-11-29 27 views
41

Khi gỡ lỗi tập lệnh Python, tôi thực sự muốn biết toàn bộ ngăn xếp cuộc gọi cho toàn bộ chương trình của mình. Một tình huống lý tưởng sẽ là nếu có một cờ dòng lệnh cho python có thể khiến Python in tất cả các tên hàm khi chúng được gọi (tôi đã kiểm tra man Python2.7, nhưng không tìm thấy bất kỳ thứ gì thuộc loại này).Làm cách nào để in các chức năng khi chúng được gọi là

Do số lượng hàm trong tập lệnh này, tôi không muốn thêm câu lệnh in vào đầu mỗi chức năng và/hoặc lớp học, nếu có thể.

Một giải pháp trung gian sẽ là sử dụng trình gỡ lỗi của PyDev, đặt một vài điểm ngắt và kiểm tra ngăn xếp cuộc gọi cho các điểm đã cho trong chương trình của tôi, vì vậy tôi sẽ sử dụng phương pháp này trong thời gian này.

Tôi vẫn muốn xem danh sách đầy đủ tất cả các chức năng được gọi trong suốt vòng đời của chương trình, nếu phương pháp đó tồn tại.

+1

profilers cho bạn biết tất cả các chức năng được gọi là ví dụ http://docs.python.org/library/profile.html nhưng không chính xác những gì bạn yêu cầu - điều này có đủ không? – Mark

Trả lời

70

Bạn có thể làm điều này với một hàm trace (đạo cụ để Spacedman để cải thiện phiên bản gốc của này để theo dõi lợi nhuận và sử dụng một số thụt đẹp):

def tracefunc(frame, event, arg, indent=[0]): 
     if event == "call": 
      indent[0] += 2 
      print "-" * indent[0] + "> call function", frame.f_code.co_name 
     elif event == "return": 
      print "<" + "-" * indent[0], "exit function", frame.f_code.co_name 
      indent[0] -= 2 
     return tracefunc 

import sys 
sys.settrace(tracefunc) 

main() # or whatever kicks off your script 

Lưu ý rằng đối tượng mã của một chức năng thường có cùng tên là hàm liên kết, nhưng không phải lúc nào, vì các hàm có thể được tạo động. Thật không may, Python không theo dõi các đối tượng hàm trên ngăn xếp (đôi khi tôi đã mơ tưởng về việc gửi một bản vá cho việc này). Tuy nhiên, điều này chắc chắn là "đủ tốt" trong hầu hết các trường hợp.

Nếu điều này trở thành vấn đề, bạn có thể trích xuất tên hàm "thực" từ mã nguồn — Python theo dõi tên tệp và số dòng — hoặc yêu cầu bộ thu gom rác tìm ra đối tượng hàm nào đề cập đến đối tượng mã. Có thể có nhiều hơn một hàm chia sẻ đối tượng mã, nhưng bất kỳ tên nào của chúng có thể đủ tốt.

Coming back to lại này bốn năm sau, nó behooves tôi kể rằng trong Python 2.6 và sau đó, bạn có thể có được hiệu suất tốt hơn bằng cách sử dụng sys.setprofile() hơn sys.settrace(). Chức năng theo dõi tương tự có thể được sử dụng; nó chỉ là chức năng profile được gọi chỉ khi một hàm được nhập vào hoặc thoát, vì vậy những gì bên trong hàm thực hiện ở tốc độ tối đa.

+0

+1 cho mã thực. –

+1

Tôi đã tinh chỉnh để hiển thị trả về hàm. hy vọng thats okay! – Spacedman

+0

chắc chắn, càng nhiều càng tốt :-) – kindall

2
import traceback 
def foo(): 
    traceback.print_stack() 
def bar(): 
    foo() 
def car(): 
    bar(): 

car() 
File "<string>", line 1, in <module> 
File "C:\Python27\lib\idlelib\run.py", line 97, in main 
    ret = method(*args, **kwargs) 
File "C:\Python27\lib\idlelib\run.py", line 298, in runcode 
    exec code in self.locals 
File "<pyshell#494>", line 1, in <module> 
File "<pyshell#493>", line 2, in car 
File "<pyshell#490>", line 2, in bar 
File "<pyshell#486>", line 2, in foo 

traceback

+1

Đây chỉ là một cách ít thuận tiện và ít linh hoạt hơn để thực hiện những gì OP đã làm bằng cách sử dụng trình gỡ lỗi và điểm ngắt. –

7

Có một vài lựa chọn. Nếu trình gỡ lỗi không đủ, bạn có thể đặt chức năng theo dõi bằng cách sử dụng sys.settrace(). Hàm này về cơ bản sẽ được gọi trên mọi dòng mã Python được thực thi, nhưng nó dễ dàng xác định các cuộc gọi hàm - xem tài liệu được liên kết.

Bạn cũng có thể quan tâm đến mô-đun trace, mặc dù nó không thực hiện chính xác những gì bạn yêu cầu. Hãy chắc chắn xem xét tùy chọn --trackcalls.

+0

Vâng, 'sys.settrace()', kết hợp với chức năng dò vết gợi ý của @ kindall ở trên làm việc như một sự quyến rũ. :) Mô-đun 'dấu vết' trông rất hữu ích, quá ... Tôi sẽ ghi nhớ nó cho các dự án gỡ lỗi trong tương lai. – James

2

Bạn có thể sử dụng settrace, như được nêu ở đây: Tracing python code. Sử dụng phiên bản gần cuối trang. Tôi dán mã của trang đó vào mã của tôi để xem chính xác những dòng nào được thực hiện khi mã của tôi đang chạy. Bạn cũng có thể lọc để bạn chỉ thấy tên của các hàm được gọi.

5

Một công cụ tốt để nhận thức được là trace mô-đun:

$ cat foo.py 
def foo(): 
    bar() 

def bar(): 
    print "in bar!" 

foo() 

$ python -m trace --listfuncs foo.py 
in bar! 

functions called: 
filename: /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/trace.py, modulename: trace, funcname: _unsettrace 
filename: foo.py, modulename: foo, funcname: 
filename: foo.py, modulename: foo, funcname: bar 
filename: foo.py, modulename: foo, funcname: foo 

$python -m trace --trace foo.py 
--- modulename: foo, funcname: 
foo.py(1): def foo(): 
foo.py(4): def bar(): 
foo.py(7): foo() 
--- modulename: foo, funcname: foo 
foo.py(2): bar() 
--- modulename: foo, funcname: bar 
foo.py(5): print "in bar!" 
in bar! 
--- modulename: trace, funcname: _unsettrace 
trace.py(80):   sys.settrace(None) 

+1

'dấu vết' là hữu ích, nhưng tôi không thể tìm cách tạo ra kết quả được yêu cầu bởi OP: '-l' chỉ hiển thị từng hàm một lần,' -t' hiển thị mọi dòng. –

Các vấn đề liên quan