Вимкніть твердження в Python


90

Як вимкнути твердження в Python?

Тобто, якщо твердження не вдається, я не хочу, щоб воно підкидало AssertionError, а продовжувало.

Як це зробити?

Відповіді:


75

Як вимкнути твердження в Python?

Існує безліч підходів, які впливають на один процес, середовище або один рядок коду.

Я демонструю кожен.

На весь процес

Використання -Oпрапора (велике O) відключає всі твердження в процесі.

Наприклад:

$ python -Oc "assert False"

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

Зверніть увагу, що під деактивуванням я маю на увазі, що він також не виконує вираз, що йде за ним:

$ 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

Для навколишнього середовища

Ви також можете використовувати змінну середовища для встановлення цього прапора.

Це вплине на кожен процес, який використовує або успадковує середовище.

Наприклад, у Windows встановлення та очищення змінної середовища:

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

Те саме в Unix (використання набору та зняття для відповідної функціональності)

Одна точка в коді

Ви продовжуєте своє запитання:

якщо твердження не вдається, я не хочу, щоб воно викидало AssertionError, а продовжувало.

Якщо ви хочете, щоб код, який не вдається здійснити, ви можете переконатися або переконатися, що потік управління не досягає твердження, наприклад:

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

або ви можете вловити помилку твердження:

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

який друкує:

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

і ви будете продовжувати рухатися з того моменту, з яким ви обробляли AssertionError.

Список літератури

З в assertдокументації :

Таке твердження:

assert expression #, optional_message

Еквівалентно

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

І,

вбудована змінна __debug__знаходиться Trueза звичайних обставин, Falseколи вимагається оптимізація (опція командного рядка -O).

і далі

Призначення __debug__незаконним. Значення для вбудованої змінної визначається під час запуску інтерпретатора.

З документації щодо використання:

Увімкніть базові оптимізації. Це змінює розширення імені для скомпільованих (байт-кодів) файлів із .pyc на .pyo. Див. Також PYTHONOPTIMIZE.

і

ПІТОНОПТИМІЗУЙТЕ

Якщо для цього значення встановлено непустий рядок, це еквівалентно зазначенню -Oпараметра. Якщо встановлено ціле число, це еквівалентно зазначенню -Oкілька разів.


чи можна було б пропустити код, який не спрацьовує у випадку "Єдиної точки в коді"? Я спробував встановити __debug__значення False, але це заборонено.
Matthijs

1
@Matthijs, ви можете або переконатися, що потік управління не досягає його (наприклад if False: assert False), або ви можете вловити помилку твердження. Це ваш вибір. Оновлено відповідь для вирішення вашого питання.
Аарон Холл

Дякую за відповідь, але ще не повністю, про що я думав. Я хотів би відключити стверджує всередині функції під час виконання, в ідеалі з якою - то менеджер контексту: твердження оцінюється: foo()і комутаційні затвердження від: with skip_assertion(): foo(). Перевага цього в тому, що мені не потрібно додавати ще один прапор до функції
Matthijs

2
Ви можете переписати байт-код функції, переписати AST або саму функцію. (вручну або програмно, для будь-якого). Переписування AST було б, мабуть, найбільш надійним підходом ("просто" замінити Assertоб'єкти на Passоб'єкти). Менеджер контексту безпосередньо не працював би для цього, але ви могли б мати якийсь механізм, який таким чином використовував оформлені функції. Незалежно від того, я не рекомендую це. Я підозрюю, що ваша причина того, що ви хочете це зробити, полягає в тому, що ви викликаєте код, який ви не контролюєте, і отримуєте AssertionErrors. Якщо так, вам, ймовірно, потрібно знайти інше виправлення.
Аарон Холл

59

Виклик Python із позначкою -O:

test.py:

assert(False)
print 'Done'

Вихід:

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
Асерт не є функцією, тому парени зайві.
Зал Аарона

15

Обидві вже подані відповіді є вірними (зателефонуйте Python за допомогою команди -Oабо -OOв командному рядку).

Ось різниця між ними:

  • -OУвімкніть базові оптимізації. Це змінює розширення імені для скомпільованих (байт-кодів) файлів із .pyc на .pyo.

  • -OOНа додаток до -Oоптимізацій відкиньте документацію .

документації Python )



3

Вам НЕ слід вимикати (більшість) тверджень. Вони ловлять непередбачувані помилки, коли увага в іншому місці. Див. Правило 5 у "Силі десяти" .

Натомість, охороняйте деякі дорогі перевірки тверджень чимось на зразок:

import logging
logger = logging.getLogger(__name__)

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

Один із способів зберегти важливі твердження та дозволити assertоптимізувати твердження - це підняти їх у виборі:

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

1
//, Однак проблема полягає в тому, що твердження все ще додає цикломатичної складності, а обробка помилок повинна обробляти все інше?
Натан Басанезе,

1
Твердження, які слід захищати, як зазначено вище, є дорогими дзвінками, які значно уповільнюють виконання. Для деяких алгоритмів перевірка такого роду може тривати на порядок довше, ніж вся програма. Подумайте про те, щоб запустити наївну, але простішу реалізацію (так менше шансів містити помилки) того самого алгоритму, щоб перевірити правильність. Або перевірка вичерпним переліком чогось, про що не може бути й мови для нормальної роботи.
Йоанніс Філіппідіс,

Я не бачу особливої ​​проблеми з читабельністю, оскільки такий вислів не додає вкладеності в код. Витяг його як виклику функції може зрушити його з місця, якщо це проблема (і я сподіваюся, що такий рефакторинг повинен зменшити цикломатичну складність). У будь-якому випадку, цикломатична складність не повинна регулювати перевірку безпеки.
Йоанніс Філіппідіс,

2

Запуск в оптимізованому режимі повинен це зробити:

python -OO module.py
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.