(Cập nhật ngày 28 tháng 5 năm 2016) Sử dụng RealGUD trong Emacs
Đối với bất kỳ ai trong Emacs, chuỗi này cho biết cách hoàn thành mọi thứ được mô tả trong OP (và hơn thế nữa) bằng cách sử dụng
- một trình gỡ lỗi quan trọng mới trong Emacs được gọi là RealGUD có thể hoạt động với bất kỳ trình gỡ lỗi nào (bao gồm
ipdb
).
- Gói Emacs
isend-mode
.
Sự kết hợp của hai gói này cực kỳ mạnh mẽ và cho phép một người tái tạo chính xác hành vi được mô tả trong OP và thậm chí còn làm nhiều hơn thế.
Thông tin thêm về bài viết wiki của RealGUD cho ipdb.
Câu trả lời gốc:
Sau khi đã thử nhiều phương pháp khác nhau để gỡ lỗi Python, bao gồm mọi thứ được đề cập trong luồng này, một trong những cách gỡ lỗi ưa thích của tôi với Python bằng IPython là với các shell nhúng.
Xác định trình bao IPython nhúng tùy chỉnh:
Thêm phần sau vào tập lệnh vào tập lệnh của bạn PYTHONPATH
để phương thức ipsh()
trở nên khả dụng.
import inspect
# First import the embed function
from IPython.terminal.embed import InteractiveShellEmbed
from IPython.config.loader import Config
# Configure the prompt so that I know I am in a nested (embedded) shell
cfg = Config()
prompt_config = cfg.PromptManager
prompt_config.in_template = 'N.In <\\#>: '
prompt_config.in2_template = ' .\\D.: '
prompt_config.out_template = 'N.Out<\\#>: '
# Messages displayed when I drop into and exit the shell.
banner_msg = ("\n**Nested Interpreter:\n"
"Hit Ctrl-D to exit interpreter and continue program.\n"
"Note that if you use %kill_embedded, you can fully deactivate\n"
"This embedded instance so it will never turn on again")
exit_msg = '**Leaving Nested interpreter'
# Wrap it in a function that gives me more context:
def ipsh():
ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg)
frame = inspect.currentframe().f_back
msg = 'Stopped at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame)
# Go back one level!
# This is needed because the call to ipshell is inside the function ipsh()
ipshell(msg,stack_depth=2)
Sau đó, bất cứ khi nào tôi muốn gỡ lỗi một cái gì đó trong mã của mình, tôi đặt ipsh()
ngay tại vị trí mà tôi cần kiểm tra đối tượng, v.v. Ví dụ: giả sử tôi muốn gỡ lỗimy_function
bên dưới
Sử dụng nó:
def my_function(b):
a = b
ipsh() # <- This will embed a full-fledged IPython interpreter
a = 4
và sau đó tôi gọi my_function(2)
theo một trong những cách sau:
- Hoặc bằng cách chạy chương trình Python gọi hàm này từ shell Unix
- Hoặc bằng cách gọi nó trực tiếp từ IPython
Bất kể tôi gọi nó như thế nào, thông dịch viên dừng lại ở dòng nói ipsh()
. Khi bạn đã hoàn tất, bạn có thể làm Ctrl-D
và Python sẽ tiếp tục thực hiện (với bất kỳ cập nhật biến nào mà bạn đã thực hiện). Lưu ý rằng, nếu bạn chạy mã từ IPython thông thường, vỏ IPython (trường hợp 2 ở trên), vỏ IPython mới sẽ được lồng bên trong cái mà bạn đã gọi nó, điều này hoàn toàn tốt, nhưng bạn nên biết. Dù sao, một khi trình thông dịch dừng ở vị trí của ipsh
, tôi có thể kiểm tra giá trị của a
(đó là 2
), xem các chức năng và đối tượng được xác định, v.v.
Vấn đề:
Giải pháp ở trên có thể được sử dụng để Python dừng bất cứ nơi nào bạn muốn trong mã của mình và sau đó thả bạn vào một trình thông dịch IPython chính thức. Thật không may, nó không cho phép bạn thêm hoặc xóa các điểm dừng một khi bạn gọi tập lệnh, điều này rất khó chịu. Theo tôi, đây là duy nhất điều nhất ngăn IPython trở thành một công cụ sửa lỗi tuyệt vời cho Python.
Điều tốt nhất bạn có thể làm bây giờ:
Cách giải quyết là đặt ipsh()
một ưu tiên tại các vị trí khác nhau nơi bạn muốn trình thông dịch Python khởi chạy trình bao IPython (tức là a breakpoint
). Sau đó, bạn có thể "nhảy" giữa các "điểm dừng" được mã hóa cứng được xác định trước khác nhau Ctrl-D
, để thoát khỏi vỏ IPython được nhúng hiện tại và dừng lại bất cứ khi nào trình thông dịch nhấn vào cuộc gọi tiếp theoipsh()
.
Nếu bạn đi theo tuyến đường này, một cách để thoát khỏi "chế độ gỡ lỗi" và bỏ qua tất cả các điểm dừng tiếp theo, là sử dụng ipshell.dummy_mode = True
nó sẽ khiến Python bỏ qua mọi cảnh báo tiếp theo của ipshell
đối tượng mà chúng ta đã tạo ở trên.
!
lệnh thực thi bất kỳ lệnh python nào tại breakpoint