Какая польза от "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:
Первое утверждение ничего не делает, а второе вызывает исключение. Это первая подсказка: утверждения полезны для проверки условий, которые должны быть истинными в заданной позиции вашего кода (обычно, начало (предусловия) и конец функции (постусловия)).
Утверждения на самом деле тесно связаны с программированием по контракту, что является очень полезной инженерной практикой:
Из документов:
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
. Таким образом, ваше выражение утверждения будет чем-то, чего вы не хотите в своей программе.
например
assert <condition>
- использование assert без<error message>
var = int(input("Enter value 1-9 inclusive:")) assert var!=0 print(var)
Вывод:
Если ввод 0:
AssertionError
Если вход 1:
1
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
Ключевые моменты:
- Он используется как средство отладки.
- Требуется выражение и необязательное сообщение.
- Он существует почти во всех языках программирования.
По сути, ключевое слово 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
>>>