(Pembaruan pada 28 Mei 2016) Menggunakan RealGUD di Emacs
Bagi siapa pun di Emacs, utas ini menunjukkan cara menyelesaikan semua yang dijelaskan dalam OP (dan banyak lagi) menggunakan
- debugger penting baru di Emacs yang disebut RealGUD yang dapat beroperasi dengan debugger apa pun (termasuk
ipdb
).
- Paket Emacs
isend-mode
.
Kombinasi kedua paket ini sangat kuat dan memungkinkan seseorang untuk menciptakan kembali persis perilaku yang dijelaskan dalam OP dan melakukan lebih banyak lagi.
Info lebih lanjut tentang artikel wiki dari RealGUD untuk ipdb.
Jawaban asli:
Setelah mencoba berbagai metode untuk men-debug Python, termasuk semua yang disebutkan dalam utas ini, salah satu cara yang saya sukai untuk men-debug Python dengan IPython adalah dengan shell yang tertanam.
Mendefinisikan shell IPython tertanam yang kustom:
Tambahkan berikut ini pada skrip ke Anda PYTHONPATH
, sehingga metode ipsh()
menjadi tersedia.
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)
Kemudian, setiap kali saya ingin men-debug sesuatu dalam kode saya, saya menempatkan ipsh()
tepat di lokasi di mana saya perlu melakukan pemeriksaan objek, dll. Misalnya, katakan saya ingin men-debug di my_function
bawah ini
Menggunakannya:
def my_function(b):
a = b
ipsh() # <- This will embed a full-fledged IPython interpreter
a = 4
dan kemudian saya memohon my_function(2)
dalam salah satu cara berikut:
- Baik dengan menjalankan program Python yang menjalankan fungsi ini dari shell Unix
- Atau dengan memintanya langsung dari IPython
Terlepas dari bagaimana saya memintanya, penerjemah berhenti di baris yang mengatakan ipsh()
. Setelah selesai, Anda bisa melakukannya Ctrl-D
dan Python akan melanjutkan eksekusi (dengan pembaruan variabel apa pun yang Anda buat). Perhatikan bahwa, jika Anda menjalankan kode dari IPython biasa, shell IPython (kasus 2 di atas), shell IPython yang baru akan disarangkan di dalam yang Anda gunakan, yang benar-benar baik-baik saja, tetapi perlu diperhatikan. Bagaimanapun, begitu penerjemah berhenti di lokasi ipsh
, saya dapat memeriksa nilai a
(yang 2
), melihat fungsi dan objek apa yang didefinisikan, dll
Masalah:
Solusi di atas dapat digunakan untuk menghentikan Python di mana pun Anda inginkan dalam kode Anda, dan kemudian menjatuhkan Anda ke penerjemah IPython sepenuhnya. Sayangnya itu tidak memungkinkan Anda menambah atau menghapus breakpoints setelah Anda menjalankan skrip, yang sangat membuat frustrasi. Menurut pendapat saya, ini adalah satu - satunya hal yang mencegah IPython menjadi alat debugging yang bagus untuk Python.
Yang terbaik yang dapat Anda lakukan untuk saat ini:
Solusinya adalah menempatkan ipsh()
apriori di lokasi yang berbeda di mana Anda ingin juru bahasa Python meluncurkan shell IPython (yaitu a breakpoint
). Anda kemudian dapat "melompat" di antara "breakpoint" berbeda yang ditentukan sebelumnya, dengan kode keras Ctrl-D
, yang akan keluar dari shell IPython yang tertanam saat ini dan berhenti lagi setiap kali penerjemah menghantam panggilan berikutnya ipsh()
.
Jika Anda menggunakan rute ini, salah satu cara untuk keluar dari "mode debugging" dan mengabaikan semua breakpoints berikutnya, adalah dengan menggunakan ipshell.dummy_mode = True
yang akan membuat Python mengabaikan instantiations berikutnya dari ipshell
objek yang kita buat di atas.
!
perintah yang mengeksekusi perintah python di breakpoint