Menggunakan pernyataan cetak hanya untuk debug

109

Saya telah banyak coding dengan Python akhir-akhir ini. Dan saya telah bekerja dengan data yang belum pernah saya tangani sebelumnya, menggunakan rumus yang belum pernah dilihat sebelumnya dan menangani file besar. Semua ini membuat saya menulis banyak pernyataan cetak untuk memverifikasi apakah semuanya berjalan dengan baik dan mengidentifikasi titik-titik kegagalan. Namun, secara umum, mengeluarkan begitu banyak informasi bukanlah praktik yang baik. Bagaimana cara menggunakan pernyataan cetak hanya ketika saya ingin men-debug dan membiarkannya dilewati ketika saya tidak ingin mereka dicetak?

crazyaboutliv
sumber

Jawaban:

161

The loggingmodul memiliki segala sesuatu yang Anda inginkan. Ini mungkin tampak berlebihan pada awalnya, tetapi gunakan hanya bagian yang Anda butuhkan. Saya akan merekomendasikan menggunakan logging.basicConfiguntuk beralih tingkat penebangan untuk stderrdan metode log sederhana , debug, info, warning, errordan critical.

import logging, sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
logging.debug('A debug message!')
logging.info('We processed %d records', len(processed_records))
Matt Joiner
sumber
5
Juga, jika Anda mengalami masalah saat menginstal modul ini seperti saya; logging adalah bagian dari pustaka standar - tidak perlu menginstal pip bahkan saat menggunakan lingkungan virtual
Amr
Bagaimana cara menyetel tingkat logging sedemikian rupa sehingga hanya mencetak kesalahan dan bukan men-debug pesan?
Eduardo Pignatelli
@EduardoPignatelli mengatur level, dalam basicConfigpanggilan, ke logging.ERROR.
Matt Joiner
Saya khawatir ini tidak berfungsi di lab jupyter 1.2.6. Anda dapat mengatur tingkat logging sekali, dan pengaturan ulang menggunakan tidak logging.basicConfig(stream=sys.stderr, level=logging.ERROR)akan berpengaruh. Memulai ulang kernel dan mengatur level baru berfungsi, tetapi itu adalah solusi bagi saya.
Eduardo Pignatelli
@EduardoPignatelli Anda harus mengajukan pertanyaan lain untuk ini. Tetapi kemungkinan besar Anda harus mengubah level secara langsung pada root logger, jupyter mungkin memanggil basicConfig sebelum Anda.
Matt Joiner
28

Cara sederhana untuk melakukannya adalah dengan memanggil fungsi logging:

DEBUG = True

def log(s):
    if DEBUG:
        print s

log("hello world")

Kemudian Anda dapat mengubah nilai DEBUGdan menjalankan kode Anda dengan atau tanpa logging.

loggingModul standar memiliki mekanisme yang lebih rumit untuk ini.

Greg Hewgill
sumber
5
Mungkin lebih baik dalam jangka panjang menggunakan modul logging yang disediakan daripada menggulung modul Anda sendiri (meskipun ini terlihat lebih rumit).
mgiuca
11
Benar, tapi ada baiknya memahami bagaimana seseorang bisa menggulung sendiri.
Greg Hewgill
1
Memang. Di atas adalah ide bagus tentang cara loggingkerjanya (pada tingkat yang sangat sederhana).
mgiuca
Ini yang saya gunakan untuk aws lambda saya.
crsuarezf
21

Gunakan modul perpustakaan built-in logging daripada mencetak.

Anda membuat Loggerobjek (katakanlah logger), lalu setelah itu, setiap kali Anda menyisipkan cetakan debug, Anda cukup meletakkan:

logger.debug("Some string")

Anda dapat menggunakan logger.setLeveldi awal program untuk mengatur tingkat keluaran. Jika Anda menyetelnya ke DEBUG, semua debug akan dicetak. Setel ke INFO atau lebih tinggi dan segera semua debug akan hilang.

Anda juga dapat menggunakannya untuk mencatat hal-hal yang lebih serius, pada level yang berbeda (INFO, PERINGATAN, dan ERROR).

mgiuca
sumber
12

Pertama, saya akan kedua nominasi kerangka logging python . Namun, berhati-hatilah saat menggunakannya. Secara khusus: biarkan kerangka logging memperluas variabel Anda, jangan lakukan sendiri. Misalnya, alih-alih:

logging.debug("datastructure: %r" % complex_dict_structure)

pastikan Anda melakukan:

logging.debug("datastructure: %r", complex_dict_structure)

karena meskipun terlihat serupa, versi pertama akan dikenakan biaya repr () meskipun dinonaktifkan . Versi kedua menghindari ini. Demikian pula, jika Anda menggulung sendiri, saya menyarankan sesuatu seperti:

def debug_stdout(sfunc):
    print(sfunc())

debug = debug_stdout

dipanggil melalui:

debug(lambda: "datastructure: %r" % complex_dict_structure)

yang akan, sekali lagi, menghindari overhead jika Anda menonaktifkannya dengan melakukan:

def debug_noop(*args, **kwargs):
    pass

debug = debug_noop

Overhead komputasi string tersebut mungkin tidak masalah kecuali jika 1) mahal untuk dihitung atau 2) pernyataan debug berada di tengah, katakanlah, loop n ^ 3 atau sesuatu. Bukannya aku tahu apa-apa tentang itu.

pjz
sumber
Ada lebih banyak informasi tentang topik penting ini di bawah 'pengoptimalan' di petunjuk pembuatan log: docs.python.org/3/howto/logging.html#optimization
Martin CR
7

Saya tidak tahu tentang orang lain, tapi saya terbiasa mendefinisikan "konstanta global" ( DEBUG) dan kemudian fungsi global ( debug(msg)) yang msghanya akan mencetak jika DEBUG == True.

Kemudian saya menulis pernyataan debug saya seperti:

debug('My value: %d' % value)

... kemudian saya mengambil unit testing dan tidak pernah melakukan ini lagi! :)

Mac
sumber
Pengujian unit ha. Oke, itu hal lain untuk diambil kalau begitu :(
crazyaboutliv
1
Saya tidak ingin menghalangi pengujian unit - ini penting. Tapi menurut saya ini bukan pengganti logging, bahkan sebagai teknik debugging. Saya masih melakukan banyak pencetakan untuk menguji berbagai hal dengan cepat.
mgiuca
@crazyaboutliv - Pengujian unit yang dilakukan dengan benar sangat bagus. Lihat bab menyelam ke dalam python ini untuk presentasi yang tajam, ringkas, dan mudah diikuti
mac
@mgiuca - Saya juga melakukan pencetakan cepat, tetapi itu hanya beberapa atau lebih print()sambil membawa kode saya ke tingkat yang diperlukan untuk lulus ujian. Saya tidak pernah berakhir dengan jumlah besar di print()semua tempat. Logging juga keren! :)
mac
2
@mac Sepertinya tautan Anda sekarang membutuhkan 'www' eksplisit - sekarang dihosting di sini .
culix