Chỉ sử dụng câu lệnh in để gỡ lỗi


109

Tôi đã viết mã rất nhiều bằng Python trong thời gian gần đây. Và tôi đã làm việc với dữ liệu mà tôi chưa từng làm việc trước đây, sử dụng các công thức chưa từng thấy trước đây và xử lý các tệp lớn. Tất cả những điều này khiến tôi phải viết rất nhiều bản báo cáo để xác minh xem mọi việc có ổn không và xác định những điểm không thành công. Tuy nhiên, nói chung, xuất ra quá nhiều thông tin không phải là một cách thực hành tốt. Làm cách nào để chỉ sử dụng câu lệnh in khi tôi muốn gỡ lỗi và bỏ qua chúng khi tôi không muốn in chúng?

Câu trả lời:


161

Các loggingmô-đun có mọi thứ bạn có thể muốn. Thoạt nghe có vẻ thừa nhưng chỉ sử dụng những phần bạn cần. Tôi khuyên bạn nên sử dụng logging.basicConfigđể chuyển đổi mức độ khai thác gỗ để stderrphương pháp đơn giản log , 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
Ngoài ra, trong trường hợp bạn gặp sự cố khi cài đặt mô-đun này như tôi; khai thác gỗ là một phần của thư viện chuẩn - không cần cài đặt pip ngay cả khi sử dụng một môi trường ảo
Amr

Làm cách nào để thiết lập mức độ ghi nhật ký sao cho nó chỉ in ra các lỗi và không gỡ lỗi các thông báo?
Eduardo Pignatelli

@EduardoPignatelli đã đặt level, trong basicConfigcuộc gọi, thành logging.ERROR.
Matt Joiner

Tôi e rằng điều này không hoạt động trên jupyter lab 1.2.6. Bạn có thể đặt cấp độ ghi nhật ký một lần và việc thiết lập lại đang sử dụng logging.basicConfig(stream=sys.stderr, level=logging.ERROR)sẽ không có hiệu lực. Khởi động lại hạt nhân và thiết lập cấp độ mới hoạt động, nhưng đó là một giải pháp cho tôi.
Eduardo Pignatelli

@EduardoPignatelli bạn nên đặt một câu hỏi khác cho điều này. Nhưng có thể bạn sẽ cần trực tiếp thay đổi cấp độ trên root log, jupyter có thể đang gọi basicConfig trước bạn.
Matt Joiner

28

Một cách đơn giản để làm điều này là gọi một hàm ghi nhật ký:

DEBUG = True

def log(s):
    if DEBUG:
        print s

log("hello world")

Sau đó, bạn có thể thay đổi giá trị của DEBUG và chạy mã của mình có hoặc không ghi nhật ký.

loggingMô-đun tiêu chuẩn có một cơ chế phức tạp hơn cho việc này.


5
Về lâu dài, có lẽ tốt hơn nếu sử dụng mô-đun ghi nhật ký được cung cấp hơn là sử dụng mô-đun ghi nhật ký của riêng bạn (mặc dù nó trông phức tạp hơn).
mgiuca

11
Đúng, nhưng thật đáng giá khi hiểu cách người ta có thể tự cuộn.
Greg Hewgill

1
Thật. Trên đây là một ý tưởng hay về cách thức logginghoạt động (ở mức độ rất đơn giản).
mgiuca

Đây là cái mà tôi sử dụng cho lambdas của mình.
crsuarezf

21

Sử dụng mô-đun thư viện tích hợp ghi nhật ký thay vì in.

Bạn tạo một Loggerđối tượng (giả sử logger), và sau đó, bất cứ khi nào bạn chèn bản in gỡ lỗi, bạn chỉ cần đặt:

logger.debug("Some string")

Bạn có thể sử dụng logger.setLevelkhi bắt đầu chương trình để đặt mức đầu ra. Nếu bạn đặt nó thành Gỡ lỗi, nó sẽ in tất cả các bản gỡ lỗi. Đặt nó thành INFO hoặc cao hơn và ngay lập tức tất cả các gỡ lỗi sẽ biến mất.

Bạn cũng có thể sử dụng nó để ghi lại những thứ nghiêm trọng hơn, ở các cấp độ khác nhau (THÔNG TIN, CẢNH BÁO và LỖI).


12

Đầu tiên, tôi sẽ đề cử thứ hai về khung ghi nhật ký của python . Tuy nhiên, hãy cẩn thận một chút về cách bạn sử dụng nó. Cụ thể: hãy để khung ghi nhật ký mở rộng các biến của bạn, đừng tự làm điều đó. Ví dụ, thay vì:

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

hãy chắc chắn rằng bạn làm:

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

bởi vì trong khi chúng trông giống nhau, phiên bản đầu tiên phải chịu chi phí repr () ngay cả khi nó bị vô hiệu hóa . Phiên bản thứ hai tránh điều này. Tương tự như vậy, nếu bạn tự cuộn, tôi sẽ đề xuất một cái gì đó như:

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

debug = debug_stdout

được gọi qua:

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

điều này một lần nữa sẽ tránh được chi phí nếu bạn vô hiệu hóa nó bằng cách:

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

debug = debug_noop

Chi phí tính toán các chuỗi đó có lẽ không thành vấn đề trừ khi chúng 1) tốn kém để tính toán hoặc 2) câu lệnh gỡ lỗi nằm ở giữa, chẳng hạn, một vòng lặp n ^ 3 hoặc một cái gì đó. Không phải là tôi sẽ biết bất cứ điều gì về điều đó.


Có thêm thông tin về chủ đề quan trọng này trong 'tối ưu hóa' trong cách ghi nhật ký: docs.python.org/3/howto/logging.html#optimization
Martin CR

7

Tôi không biết về những người khác, nhưng tôi đã được sử dụng để xác định một "hằng số toàn cầu" ( DEBUG) và sau đó là một hàm toàn cầu ( debug(msg)) sẽ msgchỉ in nếuDEBUG == True .

Sau đó, tôi viết các câu lệnh gỡ lỗi của mình như:

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

... sau đó tôi chọn thử nghiệm đơn vị và không bao giờ làm điều này nữa! :)


Đơn vị thử nghiệm ha. Được rồi, đó là một thứ khác sẽ được chọn sau đó :(
crazyaboutliv, 5:11

1
Tôi không muốn khuyến khích thử nghiệm đơn vị - nó là điều cần thiết. Nhưng tôi không nghĩ rằng nó có thể thay thế cho việc ghi nhật ký, thậm chí là một kỹ thuật gỡ lỗi. Tôi vẫn in rất nhiều để nhanh chóng kiểm tra mọi thứ.
mgiuca

@crazyaboutliv - Kiểm tra đơn vị được thực hiện đúng cách là rất tốt. Hãy xem chương này để tìm hiểu về trăn để có một bản trình bày ngắn gọn, ngắn gọn, dễ theo dõi
mac

@mgiuca - Tôi cũng in nhanh, nhưng chỉ là một vài lần print()trong khi đưa mã của tôi lên mức cần thiết để vượt qua bài kiểm tra. Tôi không bao giờ kết thúc với số lượng lớn ở print()khắp nơi. Ghi nhật ký cũng thú vị! :)
mac

2
@mac Có vẻ như liên kết của bạn hiện yêu cầu 'www' rõ ràng - nó hiện được lưu trữ ở đây .
culix
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.