Tắt các xác nhận trong Python


90

Làm cách nào để tắt các xác nhận trong Python?

Đó là, nếu một khẳng định không thành công, tôi không muốn nó ném đi AssertionError, nhưng vẫn tiếp tục.

Làm thế nào để làm điều đó?

Câu trả lời:


75

Làm cách nào để tắt các xác nhận trong Python?

Có nhiều cách tiếp cận ảnh hưởng đến một quy trình, môi trường hoặc một dòng mã.

Tôi chứng minh từng điều.

Đối với toàn bộ quá trình

Sử dụng -Ocờ (viết hoa O) vô hiệu hóa tất cả các câu lệnh khẳng định trong một quy trình.

Ví dụ:

$ python -Oc "assert False"

$ python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Lưu ý rằng bằng cách vô hiệu hóa, tôi có nghĩa là nó cũng không thực thi biểu thức theo sau nó:

$ python -Oc "assert 1/0"

$ python -c "assert 1/0"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

Vì môi trường

Bạn cũng có thể sử dụng một biến môi trường để đặt cờ này.

Điều này sẽ ảnh hưởng đến mọi quy trình sử dụng hoặc kế thừa môi trường.

Ví dụ: trong Windows, thiết lập và sau đó xóa biến môi trường:

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError
C:\>SET PYTHONOPTIMIZE=TRUE

C:\>python -c "assert False"

C:\>SET PYTHONOPTIMIZE=

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Tương tự trong Unix (sử dụng set và unset cho chức năng tương ứng)

Một điểm trong mã

Bạn tiếp tục câu hỏi của mình:

nếu một xác nhận không thành công, tôi không muốn nó tạo ra một AssertionError, nhưng hãy tiếp tục.

Nếu bạn muốn mã không được thực thi, bạn có thể bắt hoặc đảm bảo luồng điều khiển không đạt đến xác nhận, ví dụ:

if False:
    assert False, "we know this fails, but we don't get here"

hoặc bạn có thể gặp lỗi xác nhận:

try:
    assert False, "this code runs, fails, and the exception is caught"
except AssertionError as e:
    print(repr(e))

mà in:

AssertionError('this code runs, fails, and the exception is caught')

và bạn sẽ tiếp tục đi từ điểm bạn đã xử lý AssertionError.

Người giới thiệu

Từ các asserttài liệu :

Một tuyên bố khẳng định như thế này:

assert expression #, optional_message

Tương đương với

if __debug__:
    if not expression: raise AssertionError #(optional_message)

Và,

biến tích hợp __debug__Trueđiều kiện bình thường, Falsekhi tối ưu hóa được yêu cầu (tùy chọn dòng lệnh -O).

và xa hơn

Nhiệm vụ __debug__là bất hợp pháp. Giá trị cho biến tích hợp được xác định khi trình thông dịch khởi động.

Từ tài liệu sử dụng:

-O

Bật tính năng tối ưu hóa cơ bản. Điều này thay đổi phần mở rộng tên tệp cho các tệp đã biên dịch (bytecode) từ .pyc thành .pyo. Xem thêm PYTHONOPTIMIZE.

PYTHONOPTIMIZE

Nếu điều này được đặt thành một chuỗi không rỗng, nó tương đương với việc chỉ định -Otùy chọn. Nếu được đặt thành số nguyên, nó tương đương với việc chỉ định -Onhiều lần.


có thể bỏ qua mã không thành công trong trường hợp 'Một điểm trong mã' không? Tôi đã thử đặt __debug__thành Sai nhưng điều đó không được phép.
Matthijs

1
@Matthijs bạn có thể đảm bảo luồng điều khiển không đạt đến nó (ví dụ if False: assert False) hoặc bạn có thể gặp lỗi Xác nhận. Đó là những lựa chọn của bạn. Đã cập nhật câu trả lời để giải quyết câu hỏi của bạn.
Aaron Hall

Cảm ơn vì câu trả lời, nhưng vẫn chưa hoàn toàn là những gì tôi đang nghĩ. Tôi muốn vô hiệu hóa khẳng định bên trong một hàm trong thời gian chạy, lý tưởng với một số loại quản lý bối cảnh: khẳng định được đánh giá: foo()và khẳng định tắt: with skip_assertion(): foo(). Lợi ích của việc này là rằng tôi không cần phải thêm lá cờ khác về chức năng
Matthijs

2
Bạn có thể viết lại mã bytecode của hàm, viết lại AST hoặc viết lại chính hàm. (thủ công hoặc lập trình, cho cả hai). Viết lại AST có lẽ sẽ là cách tiếp cận đáng tin cậy nhất ("chỉ đơn giản là" thay thế Assertcác đối tượng bằng Passcác đối tượng). Một trình quản lý ngữ cảnh sẽ không trực tiếp làm việc đó, nhưng bạn có thể có một số loại cơ chế sử dụng các chức năng được trang trí theo cách đó. Bất kể, tôi không khuyên bạn nên nó. Tôi nghi ngờ lý do bạn muốn làm như vậy là bạn đang gọi mã mà bạn không kiểm soát và nhận được AssertionErrors. Nếu vậy, bạn có thể cần phải tìm một bản sửa lỗi khác.
Aaron Hall

59

Gọi Python bằng cờ -O:

test.py:

assert(False)
print 'Done'

Đầu ra:

C:\temp\py>C:\Python26\python.exe test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    assert(False)
AssertionError

C:\temp\py>C:\Python26\python.exe -O test.py
Done

8
Assert không phải là một hàm, vì vậy các parens là thừa.
Aaron Hall

15

Cả hai câu trả lời đã đưa ra đều hợp lệ (gọi Python bằng một trong hai -Ohoặc -OOtrên dòng lệnh).

Đây là sự khác biệt giữa chúng:

  • -OBật tính năng tối ưu hóa cơ bản. Điều này thay đổi phần mở rộng tên tệp cho các tệp đã biên dịch (bytecode) từ .pyc thành .pyo.

  • -OODocstrings Huỷ ngoài đến -Otối ưu hóa.

(Từ tài liệu Python )



3

Bạn KHÔNG nên vô hiệu hóa (hầu hết) các xác nhận. Họ mắc phải những lỗi không lường trước được khi sự chú ý ở nơi khác. Xem Quy tắc 5 trong "Sức mạnh của mười" .

Thay vào đó, hãy bảo vệ một số kiểm tra xác nhận đắt tiền bằng những thứ như:

import logging
logger = logging.getLogger(__name__)

if logger.getEffectiveLevel() < logging.DEBUG:
    ok = check_expensive_property()
    assert ok, 'Run !'

Một cách để giữ các xác nhận quan trọng và cho phép các assertcâu lệnh được tối ưu hóa là bằng cách nâng cao chúng trong một câu lệnh lựa chọn:

if foo_is_broken():
    raise AssertionError('Foo is broken!')

1
//, Tuy nhiên, vấn đề là câu lệnh vẫn tăng thêm độ phức tạp theo chu kỳ và việc xử lý lỗi có nên xử lý phần còn lại không?
Nathan Basanese

1
Các xác nhận sẽ được bảo vệ như trên là các cuộc gọi đắt tiền làm chậm đáng kể việc thực thi. Đối với một số thuật toán, các phép kiểm tra kiểu này có thể mất nhiều thời gian hơn toàn bộ chương trình. Hãy nghĩ đến việc chạy một triển khai ngây thơ nhưng đơn giản hơn (vì vậy ít có khả năng chứa lỗi hơn) của cùng một thuật toán để kiểm tra tính đúng đắn. Hoặc kiểm tra bằng cách liệt kê đầy đủ một cái gì đó nằm ngoài nghi vấn để hoạt động bình thường.
Ioannis Filippidis

Tôi không thấy có nhiều vấn đề với khả năng đọc, bởi vì một câu lệnh như vậy không thêm lồng vào mã. Việc giải nén nó dưới dạng một lời gọi hàm có thể khiến nó bị lệch, nếu đó là một vấn đề (và tôi hy vọng rằng việc tái cấu trúc như vậy sẽ làm giảm độ phức tạp theo chu kỳ). Trong mọi trường hợp, độ phức tạp theo chu kỳ không nên chi phối việc kiểm tra an toàn.
Ioannis Filippidis

2

Chạy ở chế độ tối ưu hóa nên làm điều đó:

python -OO module.py
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.