Какая польза от "assert" в Python?

Я читал некоторый исходный код и в нескольких местах я видел использование assert,

Что это значит точно? Каково его использование?

23 ответа

Решение

assert statement exists in almost every programming language. It helps detect problems early in your program, where the cause is clear, rather than later as a side-effect of some other operation.

Когда вы делаете...

assert condition

... you're telling the program to test that condition, and immediately trigger an error if the condition is false.

In Python, it's roughly equivalent to this:

if not condition:
    raise AssertionError()

Попробуйте это в оболочке Python:

>>> assert True # nothing happens
>>> assert False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

Утверждения могут содержать необязательные сообщения, и вы можете отключить их при запуске интерпретатора.

Чтобы напечатать сообщение, если утверждение не выполнено:

assert False, "Oh no! This assertion failed!"

При беге python в оптимизированном режиме, где __debug__ является FalseУтверждения будут игнорироваться. Просто передайте -O флаг:

python -O script.py

Смотрите здесь для соответствующей документации.

Остерегайтесь скобок. Как было указано выше, в Python 3 assert это еще утверждение, поэтому по аналогии с print(..) можно экстраполировать то же самое на assert(..) или же raise(..) но ты не должен.

Это важно, потому что:

assert(2 + 2 == 5, "Houston we've got a problem")

не будет работать, в отличие от

assert 2 + 2 == 5, "Houston we've got a problem"

Причина, по которой первый не будет работать, состоит в том, что bool( (False, "Houston we've got a problem") ) оценивает True,

В заявлении assert(False) это просто лишние скобки вокруг False, которые оценивают их содержание. Но с assert(False,) скобки теперь являются кортежем, а непустой кортеж оценивается как True в логическом контексте.

Как отмечали другие ответы, assert похоже на создание исключения, если данное условие не соответствует действительности. Важным отличием является то, что операторы assert игнорируются, если вы компилируете свой код с опцией оптимизации. В документации сказано, что assert expression можно лучше описать как эквивалент

if __debug__:
   if not expression: raise AssertionError

Это может быть полезно, если вы хотите тщательно протестировать свой код, а затем выпустить оптимизированную версию, если вы довольны тем, что ни одно из ваших утверждений не сработало - когда включена оптимизация, __debug__ переменная становится ложной, и условия перестанут оцениваться. Эта функция также может вас поймать, если вы полагаетесь на утверждения и не понимаете, что они исчезли.

Цель утверждения в Python - информировать разработчиков о неисправимых ошибках в программе.

Утверждения не предназначены для оповещения об ожидаемых ошибках, например, "файл не найден", где пользователь может предпринять корректирующие действия (или просто повторить попытку).

Другой способ взглянуть на это - сказать, что утверждения - это внутренние самопроверки в вашем коде. Они работают, объявляя некоторые условия невозможными в вашем коде. Если эти условия не выполняются, это означает, что в программе есть ошибка.

Если ваша программа не содержит ошибок, эти условия никогда не возникнут. Но если один из них произойдет, программа завершится с ошибкой утверждения, точно сообщающей, какое "невозможное" условие было вызвано. Это значительно упрощает поиск и исправление ошибок в ваших программах.

Вот резюме из учебника по утверждениям Python, которые я написал:

Оператор Python assert является средством отладки, а не механизмом обработки ошибок во время выполнения. Цель использования утверждений состоит в том, чтобы позволить разработчикам быстрее находить основную причину ошибки. Ошибка утверждения никогда не должна возникать, если в вашей программе нет ошибки.

Другие уже дали вам ссылки на документацию.

Вы можете попробовать следующее в интерактивной оболочке:

>>> assert 5 > 2
>>> assert 2 > 5
Traceback (most recent call last):
  File "<string>", line 1, in <fragment>
builtins.AssertionError:

Первое утверждение ничего не делает, а второе вызывает исключение. Это первая подсказка: утверждения полезны для проверки условий, которые должны быть истинными в заданной позиции вашего кода (обычно, начало (предусловия) и конец функции (постусловия)).

Утверждения на самом деле тесно связаны с программированием по контракту, что является очень полезной инженерной практикой:

http://en.wikipedia.org/wiki/Design_by_contract.

Из документов:

Assert statements are a convenient way to insert debugging assertions into a program

Здесь вы можете прочитать больше: http://docs.python.org/release/2.5.2/ref/assert.html

Утверждение assert имеет две формы.

Простая форма, assert <expression>, эквивалентно

if __​debug__:
    if not <expression>: raise AssertionError

Расширенная форма, assert <expression1>, <expression2>, эквивалентно

if __​debug__:
    if not <expression1>: raise AssertionError, <expression2>

Утверждения - это систематический способ проверки того, что внутреннее состояние программы соответствует ожидаемому программистом с целью выявления ошибок. Смотрите пример ниже.

>>> number = input('Enter a positive number:')
Enter a positive number:-1
>>> assert (number > 0), 'Only positive numbers are allowed!'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: Only positive numbers are allowed!
>>> 

Что значит утверждать? Как это используется?

Здесь есть отличные ответы, но не на вторую часть вопроса. Несмотря на многолетний практический опыт, я только недавно понял назначение утверждений.

Другие уже объяснили, как используется, поэтому я очень краток. Вот как вы его используете:

      assert condition, "error message"

И не используйте круглые скобки, assert — это ключевое слово, а не функция.

      assert (condition, "error message")  # wrong: this never fails!

Хорошее объяснение того, как использовать assert, дано здесь: http://wiki.c2.com/?WhatAreAssertions Смысл в том, чтобы объявить инварианты в вашем коде. Инвариант — это условие, которое никогда не должно нарушаться, если только в коде нет ошибки. Думайте о них как об исполняемой документации.Это тесно связано с тем, как объектно-ориентированное программирование инкапсулирует код из внешнего мира.

Проще говоря: вы должны использовать утверждение как комментарий в своем коде для других разработчиков. Но это лучше, чем комментарий, "комментарий" действительно проверяется в режиме отладки! Если нельзя ожидать, что ваша программа будет работать правильно, если утверждение будет удалено, вы используете ее неправильно. На самом деле, Python будет игнорировать все s, если вы включите оптимизацию (). Так что не полагайтесь на них, чтобы быть там. В частности, не используйте утверждения для проверки пользовательского ввода . Вместо этого создавайте исключения.

Вот хороший пример, чтобы связать все это вместе. Предположим, вы хотите иметь в своем коде специальный числовой класс, который представляет положительные целые числа, называемые . Зачем тебе это? У вас есть много функций, которые используют положительные целые числа в качестве параметров. Используя в своем коде, вам не нужно снова и снова проверять в каждой функции правильность ввода. Это гарантируется. Грубая реализация выглядит так

      class PositiveInt(int):
    # int is immutable, so we have to override new and not init
    def __new__(cls, value):
        if value <= 0:
            raise ValueError(f"{value} is not positive")
        assert value > 0, "value must be positive"
        return super(PositiveInt, cls).__new__(cls, value)   

Как видите, я использую обадля проверки ввода и в конце функции. Это кажется излишним, но только в этом тривиальном примере! Представьте, что функция немного длиннее и сложнее, поэтому не очевидно, что вы правильно проверили ввод. Утверждение в конце гарантирует, что обнаружена ошибка в вашем коде проверки. Это также делает назначение кода проверки более понятным для другого программиста, чем простой комментарий.

Резюмируя : используйтекак комментарий. Используйте его везде! Это дешево, и если это когда-нибудь станет проблемой для ваших пользователей, вы можете отключить его в выпусках с помощью.

Как кратко изложено на C2 Wiki:

Утверждение - это логическое выражение в определенной точке программы, которое будет истинным, если в программе нет ошибки.

Вы можете использовать assert заявление, чтобы документировать ваше понимание кода в конкретной точке программы. Например, вы можете задокументировать предположения или гарантии относительно входных данных (предварительных условий), состояния программы (инвариантов) или выходных данных (постусловий).

Если ваше утверждение когда-нибудь окажется неудачным, это предупреждение для вас (или вашего преемника), что вы неправильно поняли программу, когда вы ее написали, и что она, вероятно, содержит ошибку.

Для получения дополнительной информации, Джон Регер имеет замечательный пост в блоге об использовании утверждений, который относится к Python assert заявление также.

Вот простой пример, сохраните это в файле (скажем, b.py)

def chkassert(num):
    assert type(num) == int


chkassert('a')

и результат, когда $python b.py

Traceback (most recent call last):
  File "b.py", line 5, in <module>
    chkassert('a')
  File "b.py", line 2, in chkassert
    assert type(num) == int
AssertionError

assert Заявление существует практически на каждом языке программирования. Это помогает обнаруживать проблемы в начале вашей программы, где причина ясна, а не позже, как побочный эффект какой-либо другой операции. Они всегда ожидают True состояние.

Когда вы делаете что-то вроде:

assert condition

Вы говорите программе протестировать это условие и немедленно вызвать ошибку, если она ложна.

В Python assert выражение, эквивалентно:

if __debug__:
    if not <expression>: raise AssertionError

Вы можете использовать расширенное выражение для передачи необязательного сообщения:

if __debug__:
    if not (expression_1): raise AssertionError(expression_2)

Попробуйте это в интерпретаторе Python:

>>> assert True # Nothing happens because the condition returns a True value.
>>> assert False # A traceback is triggered because this evaluation did not yield an expected value.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

Есть некоторые предостережения, которые нужно увидеть, прежде чем использовать их в основном для тех, кто считает, что переключение между assert а также if заявления. Цель использовать assert в тех случаях, когда программа проверяет условие и возвращает значение, которое должно немедленно остановить программу, вместо того, чтобы использовать какой-либо альтернативный способ обойти ошибку:

1. Скобки

Как вы могли заметить, assert В заявлении используются два условия. Следовательно, не используйте скобки, чтобы использовать их как очевидный совет. Если вы делаете такие как:

assert (condition, message)

Пример:

>>> assert (1==2, 1==1)
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?

Вы будете управлять assert с (condition, message) который представляет кортеж в качестве первого параметра, и это происходит потому, что непустой кортеж в Python всегда True, Тем не менее, вы можете сделать отдельно без проблем:

assert (condition), "message"

Пример:

>>> assert (1==2), ("This condition returns a %s value.") % "False"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: This condition returns a False value.

2. Цель отладки

Если вам интересно, когда использовать assert заявление. Возьмите пример, используемый в реальной жизни:

* Когда ваша программа стремится контролировать каждый параметр, введенный пользователем или что-то еще:

def loremipsum(**kwargs):
    kwargs.pop('bar') # return 0 if "bar" isn't in parameter
    kwargs.setdefault('foo', type(self)) # returns `type(self)` value by default
    assert (len(kwargs) == 0), "unrecognized parameter passed in %s" % ', '.join(kwargs.keys())

* Другой случай по математике, когда 0 или не положительный, как коэффициент или константа для определенного уравнения:

def discount(item, percent):
    price = int(item['price'] * (1.0 - percent))
    print(price)
    assert (0 <= price <= item['price']),\
            "Discounted prices cannot be lower than 0 "\
            "and they cannot be higher than the original price."

    return price

* или даже простой пример логической реализации:

def true(a, b):
    assert (a == b), "False"
    return 1

def false(a, b):
    assert (a != b), "True"
    return 0

3. Обработка данных или проверка данных

Крайне важно не полагаться на assert оператор для выполнения обработки данных или проверки данных, потому что этот оператор может быть отключен при инициализации Python с помощью -O или же -OO flag - значение 1, 2 и 0 (по умолчанию) соответственно - или PYTHONOPTIMIZE переменная окружения.

Значение 1:

* утверждения отключены;

* файлы байт-кода генерируются с использованием .pyo расширение вместо .pyc;

* sys.flags.optimize установлен в 1 (True);

* а также, __debug__ установлен в False;

Значение 2: отключает еще один материал

* строки документов отключены;

Поэтому, используя assert Заявление о проверке своего рода ожидаемых данных чрезвычайно опасно, что подразумевает даже некоторые проблемы безопасности. Затем, если вам нужно подтвердить какое-то разрешение, я рекомендую вам raise AuthError вместо. В качестве предварительного условия, assert обычно используется программистами в библиотеках или модулях, с которыми пользователь не взаимодействует напрямую.

В Pycharm, если вы используете assert вместе с isinstance чтобы объявить тип объекта, он позволит вам получить доступ к методам и атрибутам родительского объекта во время кодирования, он будет автоматически заполнен автоматически.

Например, скажем self.object1.object2 это MyClass объект.

import MyClasss

def code_it(self):
    testObject = self.object1.object2 # at this point, program doesn't know that testObject  is a MyClass object yet
    assert isinstance(testObject , MyClasss) # now the program knows testObject is a MyClass object
    testObject.do_it() # from this point on, PyCharm will be able to auto-complete when you are working on testObject

Если оператор после assert равен true, то программа продолжается, но если оператор после assert равен false, программа выдает ошибку. Просто как тот.

например:

assert 1>0   #normal execution
assert 0>1   #Traceback (most recent call last):
             #File "<pyshell#11>", line 1, in <module>
             #assert 0>1
             #AssertionError

Если вы хотите точно знать, что зарезервированная функция делает в Python, введите help(enter_keyword)

Убедитесь, что при вводе зарезервированного ключевого слова вы вводите его в виде строки.

Python assert - это, по сути, средство отладки, которое проверяет условия для внутренней самопроверки вашего кода. Assert делает отладку действительно легкой, когда ваш код попадает в невозможные крайние случаи. Утверждают, проверяют эти невозможные случаи.

Допустим, есть функция для расчета цены товара после скидки:

def calculate_discount(price, discount):
    discounted_price = price - [discount*price]
    assert 0 <= discounted_price <= price
    return discounted_price

Здесь discounts_price никогда не может быть меньше 0 и больше фактической цены. Таким образом, в случае нарушения вышеуказанного условия assert вызывает ошибку утверждения, которая помогает разработчику определить, что произошло нечто невозможное.

Надеюсь, поможет:)

Мое краткое объяснение:

  • assert повышения AssertionError если выражение ложно, в противном случае просто продолжает код, и если есть запятая, что бы это ни было AssertionError: whatever after commaи кодировать как: raise AssertionError(whatever after comma)

Связанный учебник об этом:

https://www.tutorialspoint.com/python/assertions_in_python.htm

Как написано в других ответах, assert операторы используются для проверки состояния программы в данной точке.

Я не буду повторять то, что было сказано о связанном сообщении, скобках или -O вариант и __debug__постоянный. Также проверьте документ для получения информации из первых рук. Сосредоточусь на вашем вопросе: в чем пользаassert? Точнее, когда (а когда нет) следует использоватьassert?

В assertоператоры полезны для отладки программы, но не рекомендуется проверять вводимые пользователем данные. Я использую следующее практическое правило: сохраняйте утверждения, чтобы обнаружить, что такого не должно происходить. Пользовательский ввод может быть неправильным, например, пароль слишком короткий, но этого не должно происходить. Если диаметр круга не вдвое больше его радиуса, вы в таком случае не должны.

Самое интересное, на мой взгляд, использование assertоснован на контрактном программировании, описанном Б. Мейером в [Конструирование объектно-ориентированного программного обеспечения](https://www.eiffel.org/doc/eiffel/Object-Oriented_Software_Construction%2C_2nd_Edition) и реализован на [языке программирования Eiffel ](https://en.wikipedia.org/wiki/Eiffel_(programming_language)). Вы не можете полностью эмулировать программирование по контракту, используяassert заявление, но интересно сохранить намерение.

Вот пример. Представьте, что вам нужно написатьhead функция (например, [headфункция в Haskell](http://www.zvon.org/other/haskell/Outputprelude/head_f.html)). Вам предоставляется спецификация: "если список не пуст, вернуть первый элемент списка". Посмотрите на следующие реализации:

>>> def head1(xs): return xs[0]

А также

>>> def head2(xs):
...     if len(xs) > 0:
...         return xs[0]
...     else:
...         return None

(Да, это можно записать как return xs[0] if xs else None, но дело не в этом).

Если список не пуст, обе функции имеют одинаковый результат, и этот результат правильный:

>>> head1([1, 2, 3]) == head2([1, 2, 3]) == 1
True

Следовательно, обе реализации (я надеюсь) правильные. Они отличаются, когда вы пытаетесь взять заголовок пустого списка:

>>> head1([])
Traceback (most recent call last):
...
IndexError: list index out of range

Но:

>>> head2([]) is None
True

Опять же, обе реализации верны, потому что никто не должен передавать этим функциям пустой список (мы вышли за пределы спецификации). Это неправильный звонок, но если вы сделаете такой звонок, может случиться что угодно. Одна функция вызывает исключение, другая возвращает специальное значение. Самое главное: мы не можем полагаться на такое поведение. Еслиxs пусто, это будет работать:

print(head2(xs))

Но это приведет к сбою программы:

print(head1(xs))

Чтобы избежать сюрпризов, я хотел бы знать, когда я передаю какой-то неожиданный аргумент функции. Другими словами: я хотел бы знать, когда наблюдаемое поведение ненадежно, потому что оно зависит от реализации, а не от спецификации. Конечно, я могу прочитать спецификацию, но программисты не всегда внимательно читают документацию.

Представьте, если бы у меня был способ вставить спецификацию в код, чтобы получить следующий эффект: когда я нарушаю спецификацию, например, передав пустой список в head, Я получаю предупреждение. Это было бы большим подспорьем в написании правильной (т.е. соответствующей спецификации) программы. И вот гдеassert выходит на сцену:

>>> def head1(xs):
...     assert len(xs) > 0, "The list must not be empty"
...     return xs[0]

А также

>>> def head2(xs):
...     assert len(xs) > 0, "The list must not be empty"
...     if len(xs) > 0:
...         return xs[0]
...     else:
...         return None

Теперь у нас есть:

>>> head1([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty

А также:

>>> head2([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty

Обратите внимание, что head1 бросает AssertionError, а не IndexError. Это важно, потому чтоAssertionErrorне любая ошибка во время выполнения: она сигнализирует о нарушении спецификации. Я хотел получить предупреждение, но получаю сообщение об ошибке. К счастью, я могу отключить проверку (используя-Oвариант), но на свой страх и риск. Я сделаю это крушение действительно дорого, и надеюсь на лучшее. Представьте, что моя программа встроена в космический корабль, который путешествует через черную дыру. Я отключу утверждения и надеюсь, что программа будет достаточно надежной, чтобы не давать сбоев как можно дольше.

Этот пример касался только предварительных условий, если вы можете использовать assertдля проверки постусловий (возвращаемое значение и / или состояние) и инвариантов (состояние класса). Обратите внимание, что проверка постусловий и инвариантов с помощьюassert может быть громоздким:

  • для постусловий вам нужно присвоить возвращаемое значение переменной и, возможно, сохранить начальное состояние объекта, если вы имеете дело с методом;
  • для инвариантов вы должны проверить состояние до и после вызова метода.

У вас не будет чего-то более сложного, как Eiffel, но вы можете улучшить общее качество программы.


Подводя итог, assertЗаявление - удобный способ обнаружить, что такого не должно происходить. Нарушения спецификации (например, передача пустого списка вhead) являются первоклассными, таких ситуаций не должно происходить. Следовательно, в то время какassertможет использоваться для обнаружения любой неожиданной ситуации, это привилегированный способ гарантировать выполнение спецификации. После того, как вы вставилиassert операторов в код для представления спецификации, мы можем надеяться, что вы улучшили качество программы, потому что будут сообщаться неверные аргументы, неправильные возвращаемые значения, неправильные состояния класса...

Утверждения - это утверждения, которые уверенно констатируют факт в нашей программе.

Синтаксис: assert <condition> или же assert <condition>,<error message>

У него есть условие / выражение, которое должно быть всегда истинным. Если условие ложно, assert оператор остановит программу и выдаст сообщение об ошибке AssertionError. Таким образом, ваше выражение утверждения будет чем-то, чего вы не хотите в своей программе.

например

  1. assert <condition> - использование assert без <error message>

    var = int(input("Enter value 1-9 inclusive:"))                                 
    assert var!=0 
    print(var)
    

    Вывод:

    Если ввод 0:

    AssertionError
    

    Если вход 1:

    1
    
  2. assert <condition>,<error message> - используя assert с <error message>

    var = int(input("Enter value 1-9 inclusive:"))                                 
    assert var!=0,"Input cannot be zero"
    print(var)
    

    Вывод:

    Если ввод 0:

    AssertionError: Input cannot be zero
    

    Если вход 1:

    1
    

Ключевые моменты:

  1. Он используется как средство отладки.
  2. Требуется выражение и необязательное сообщение.
  3. Он существует почти во всех языках программирования.

По сути, ключевое слово assert означает, что если условие не является истинным, то оно выполняется через ошибку assertionerror, иначе оно продолжается, например, в python.

код-1

a=5

b=6

assert a==b

ВЫХОД:

assert a==b

AssertionError

код-2

a=5

b=5

assert a==b

ВЫХОД:

Process finished with exit code 0
def getUser(self, id, Email):

    user_key = id and id or Email

    assert user_key

Может использоваться для обеспечения передачи параметров в вызове функции.

format: assert Expression[,arguments] Когда assert встречает оператор,Python оценивает выражение. Если оператор не соответствует истине, возникает исключение (assertionError). Если утверждение не выполняется,Python использует ArgumentExpression в качестве аргумента для AssertionError. Исключения AssertionError могут быть перехвачены и обработаны, как и любое другое исключение, с помощью оператора try-кроме, но если не обработано, они завершат программу и произведут трассировку. Пример:

def KelvinToFahrenheit(Temperature):    
    assert (Temperature >= 0),"Colder than absolute zero!"    
    return ((Temperature-273)*1.8)+32    
print KelvinToFahrenheit(273)    
print int(KelvinToFahrenheit(505.78))    
print KelvinToFahrenheit(-5)    

Когда приведенный выше код выполняется, он дает следующий результат:

32.0
451
Traceback (most recent call last):    
  File "test.py", line 9, in <module>    
    print KelvinToFahrenheit(-5)    
  File "test.py", line 4, in KelvinToFahrenheit    
    assert (Temperature >= 0),"Colder than absolute zero!"    
AssertionError: Colder than absolute zero!    
>>>this_is_very_complex_function_result = 9
>>>c = this_is_very_complex_function_result
>>>test_us = (c < 4)

>>> #first we try without assert
>>>if test_us == True:
    print("YES! I am right!")
else:
    print("I am Wrong, but the program still RUNS!")

I am Wrong, but the program still RUNS!


>>> #now we try with assert
>>> assert test_us
Traceback (most recent call last):
  File "<pyshell#52>", line 1, in <module>
    assert test_us
AssertionError
>>> 
Другие вопросы по тегам