การใช้คำสั่งพิมพ์เท่านั้นในการดีบัก


109

ฉันเขียนโค้ดเป็นจำนวนมากใน Python ในช่วงปลายปี และฉันได้ทำงานกับข้อมูลที่ฉันไม่เคยทำงานมาก่อนโดยใช้สูตรที่ไม่เคยเห็นมาก่อนและจัดการกับไฟล์ขนาดใหญ่ ทั้งหมดนี้ทำให้ฉันเขียนข้อความพิมพ์จำนวนมากเพื่อตรวจสอบว่าทุกอย่างถูกต้องหรือไม่และระบุจุดที่ล้มเหลว แต่โดยทั่วไปแล้วการแสดงข้อมูลจำนวนมากไม่ใช่แนวทางปฏิบัติที่ดี ฉันจะใช้คำสั่งพิมพ์เฉพาะเมื่อฉันต้องการแก้ไขข้อบกพร่องและปล่อยให้ข้ามเมื่อไม่ต้องการให้พิมพ์ได้อย่างไร

คำตอบ:


161

loggingโมดูลมีทุกสิ่งที่คุณอาจต้องการ ในตอนแรกอาจดูเหมือนมากเกินไป แต่ใช้เฉพาะส่วนที่คุณต้องการเท่านั้น ผมขอแนะนำให้ใช้logging.basicConfigเพื่อสลับระดับการบันทึกไปstderrและวิธีการเข้าสู่ระบบที่เรียบง่าย , debug, info, warning, และerrorcritical

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))

5
นอกจากนี้ในกรณีที่คุณมีปัญหาในการติดตั้งโมดูลนี้เหมือนฉัน การบันทึกเป็นส่วนหนึ่งของไลบรารีมาตรฐาน - ไม่จำเป็นต้องติดตั้ง pip แม้ว่าจะใช้สภาพแวดล้อมเสมือนจริงก็ตาม
Amr

เราจะกำหนดระดับการบันทึกเพื่อให้พิมพ์เฉพาะข้อผิดพลาดและไม่แก้ไขข้อบกพร่องได้อย่างไร
Eduardo Pignatelli

@EduardoPignatelli ตั้งค่าlevelในการโทรไปbasicConfig logging.ERROR
Matt Joiner

ฉันกลัวว่าจะใช้ไม่ได้กับ jupyter lab 1.2.6 คุณสามารถตั้งค่าระดับการบันทึกได้เพียงครั้งเดียวและการใช้การตั้งค่าใหม่logging.basicConfig(stream=sys.stderr, level=logging.ERROR)จะไม่มีผลใด ๆ การรีสตาร์ทเคอร์เนลและการตั้งค่าระดับใหม่ใช้งานได้ แต่นั่นเป็นวิธีแก้ปัญหาสำหรับฉัน
Eduardo Pignatelli

@EduardoPignatelli คุณควรถามคำถามนี้อีก แต่เป็นไปได้ว่าคุณจะต้องเปลี่ยนระดับบน root logger โดยตรง jupyter อาจเรียก basicConfig ก่อนคุณ
Matt Joiner

28

วิธีง่ายๆในการดำเนินการนี้คือเรียกใช้ฟังก์ชันการบันทึก:

DEBUG = True

def log(s):
    if DEBUG:
        print s

log("hello world")

จากนั้นคุณสามารถเปลี่ยนค่าDEBUGและเรียกใช้รหัสของคุณโดยมีหรือไม่มีการบันทึก

loggingโมดูลมาตรฐานมีกลไกที่ซับซ้อนมากขึ้นสำหรับสิ่งนี้


5
ในระยะยาวอาจจะดีกว่าที่จะใช้โมดูลการบันทึกที่ให้มามากกว่าการม้วนของคุณเอง (แม้ว่าจะดูซับซ้อนกว่า)
mgiuca

11
จริงอยู่ แต่มันก็คุ้มค่าที่จะเข้าใจว่าเราจะหมุนตัวเองได้อย่างไร
Greg Hewgill

1
แน่นอน. ข้างต้นเป็นแนวคิดที่ดีเกี่ยวกับวิธีการloggingทำงาน (ในระดับที่ง่ายมาก)
mgiuca

นี่คือสิ่งที่ฉันใช้สำหรับ lambdas aws ของฉัน
crsuarezf

21

ใช้การเข้าสู่ระบบในตัวโมดูลห้องสมุดแทนการพิมพ์

คุณสร้างLoggerวัตถุ (พูดlogger) และหลังจากนั้นเมื่อใดก็ตามที่คุณแทรกการพิมพ์แก้จุดบกพร่องคุณเพียงแค่ใส่:

logger.debug("Some string")

คุณสามารถใช้logger.setLevelเมื่อเริ่มต้นโปรแกรมเพื่อตั้งค่าระดับเอาต์พุต หากคุณตั้งค่าเป็นดีบักมันจะพิมพ์การดีบักทั้งหมด ตั้งค่าเป็น INFO หรือสูงกว่าและทันทีการดีบักทั้งหมดจะหายไป

คุณยังสามารถใช้เพื่อบันทึกสิ่งที่ร้ายแรงกว่าในระดับต่างๆ (ข้อมูลคำเตือนและข้อผิดพลาด)


12

ก่อนอื่นฉันจะเสนอชื่อกรอบการบันทึกของ python เป็นครั้งที่สอง อย่างไรก็ตามโปรดใช้ความระมัดระวังเล็กน้อยเกี่ยวกับวิธีการใช้งาน โดยเฉพาะ: ปล่อยให้กรอบการบันทึกขยายตัวแปรของคุณอย่าทำด้วยตัวเอง ตัวอย่างเช่นแทนที่จะเป็น:

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

ให้แน่ใจว่าคุณทำ:

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

เนื่องจากแม้ว่าจะมีลักษณะคล้ายกัน แต่เวอร์ชันแรกจะมีค่าใช้จ่ายในการ repr () แม้ว่าจะปิดใช้งานก็ตาม รุ่นที่สองหลีกเลี่ยงสิ่งนี้ ในทำนองเดียวกันถ้าคุณม้วนของคุณเองฉันขอแนะนำสิ่งต่อไปนี้:

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

debug = debug_stdout

โทรผ่าน:

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

ซึ่งจะหลีกเลี่ยงค่าใช้จ่ายอีกครั้งหากคุณปิดใช้งานโดยทำ:

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

debug = debug_noop

ค่าใช้จ่ายในการคำนวณสตริงเหล่านั้นอาจไม่สำคัญเว้นแต่ว่า 1) มีราคาแพงในการคำนวณหรือ 2) คำสั่งดีบักอยู่ตรงกลางของคำสั่ง n ^ 3 loop หรืออะไรบางอย่าง ไม่ใช่ว่าฉันจะรู้อะไรเกี่ยวกับเรื่องนั้น


มีข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อสำคัญนี้ภายใต้ 'การเพิ่มประสิทธิภาพ' ในการบันทึก howto: docs.python.org/3/howto/logging.html#optimization
Martin CR

7

ผมไม่ทราบว่าเกี่ยวกับคนอื่น แต่ฉันถูกใช้ในการกำหนด"อย่างต่อเนื่องทั่วโลก" ( DEBUG) แล้วฟังก์ชั่นทั่วโลก ( debug(msg)) ที่จะพิมพ์เฉพาะในกรณีที่msgDEBUG == True

จากนั้นฉันเขียนคำสั่งดีบักของฉันเช่น:

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

... จากนั้นฉันก็รับการทดสอบหน่วยและไม่เคยทำแบบนี้อีก! :)


การทดสอบหน่วย ha. โอเคนั่นเป็นอีกสิ่งหนึ่งที่จะต้องหยิบขึ้นมา :(
crazyaboutliv

1
ฉันไม่ต้องการกีดกันการทดสอบหน่วย - เป็นสิ่งสำคัญ แต่ฉันไม่คิดว่ามันจะทดแทนการบันทึกได้แม้ว่าจะเป็นเทคนิคการดีบั๊กก็ตาม ฉันยังคงทำการพิมพ์จำนวนมากเพื่อทดสอบสิ่งต่างๆอย่างรวดเร็ว
mgiuca

@crazyaboutliv - การทดสอบหน่วยทำได้อย่างถูกต้องนั้นยอดเยี่ยมมาก ลองดูบทนี้ของการดำดิ่งสู่งูหลามเพื่อการนำเสนอที่รวดเร็วกระชับและง่ายต่อการติดตาม
Mac

@mgiuca - ฉันพิมพ์อย่างรวดเร็วเช่นกัน แต่มันเป็นเพียงไม่กี่อย่างprint()ในขณะที่นำรหัสของฉันไปสู่ระดับที่กำหนดเพื่อผ่านการทดสอบ ฉันไม่เคยลงเอยด้วยจำนวนมหาศาลprint()ทั่วทุกแห่ง การบันทึกก็เจ๋งเช่นกัน! :)
แม็ค

2
@mac ดูเหมือนว่าการเชื่อมโยงของคุณตอนนี้ต้องใช้อย่างชัดเจน 'www' - ตอนนี้มันเป็นเจ้าภาพที่นี่
culix
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.