Вопрос

  1. Есть ли проблема с производительностью или обслуживанием кода при использовании assert как часть стандартного кода вместо того, чтобы использовать его только для целей отладки?

    Является

    assert x >= 0, 'x is less than zero'
    

    лучше или хуже , чем

    if x < 0:
        raise Exception, 'x is less than zero'
    
  2. Кроме того, есть ли какой-либо способ установить бизнес-правило, например if x < 0 raise error это всегда проверяется без try/except/finally итак, если в любое время по всему коду x меньше 0, возникает ошибка, например, если вы установили assert x < 0 в начале функции, в любом месте внутри функции, где x становится меньше 0, вызывается исключение?

Это было полезно?

Решение

Чтобы иметь возможность автоматически выдавать ошибку, когда x становится меньше нуля во всей функции.Вы можете использовать дескрипторы классов.Вот один из примеров:

class LessThanZeroException(Exception):
    pass

class variable(object):
    def __init__(self, value=0):
        self.__x = value

    def __set__(self, obj, value):
        if value < 0:
            raise LessThanZeroException('x is less than zero')

        self.__x  = value

    def __get__(self, obj, objType):
        return self.__x

class MyClass(object):
    x = variable()

>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "my.py", line 7, in __set__
    raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero

Другие советы

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

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


Например, если вы пишете функцию для чтения из файла конфигурации в dict, неправильное форматирование в файле должно вызвать ConfigurationSyntaxError, в то время как вы можете assert , что ты не собираешься возвращаться None.


В вашем примере, если x является значением, установленным через пользовательский интерфейс или из внешнего источника, лучше всего использовать исключение.

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

инструкции "assert" удаляются при оптимизации компиляции.Так что, да, существуют различия как в производительности, так и в функциональности.

Текущий генератор кода не выдает никакого кода для инструкции assert, когда оптимизация запрашивается во время компиляции.- Документы Python 2.6.4

Если вы используете assert чтобы реализовать функциональность приложения, а затем оптимизировать развертывание для производства, вы будете страдать от дефектов "но-это-работает-в-разработке".

Видишь PYTHONOPTIMIZE ОПТИМИЗИРОВАТЬ и - О - ОО

Четыре цели assert

Предположим, вы работаете над 200 000 строками кода с четырьмя коллегами Элис, Берндом, Карлом и Дафной.Они называют ваш код, вы называете их код.

Тогда assert имеет четыре роли:

  1. Сообщите Алисе, Бернду, Карлу и Дафне, чего ожидает ваш код.
    Предположим, у вас есть метод, который обрабатывает список кортежей, и логика программы может прерваться, если эти кортежи не являются неизменяемыми:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))
    

    Это более достоверно, чем эквивалентная информация в документации и намного проще в обслуживании.

  2. Сообщите компьютеру, чего ожидает ваш код.
    assert обеспечивает надлежащее поведение вызывающих элементов вашего кода.Если ваш код вызывает код Алисы, а код Бернда вызывает ваш, тогда без assert, если произойдет сбой программы в коде Алисы, Бернд может предположить, что это была ошибка Алисы, Алиса проводит расследование и может предположить, что это была ваша вина, вы проводите расследование и говорите Бернду, что на самом деле это был он.Потеряно много работы.
    С asserts, кто бы ни ошибся в вызове, он быстро сможет увидеть, что это была их вина, не ваша.Элис, Бернд и вы все в выигрыше.Экономит огромное количество времени.

  3. Сообщите читателям вашего кода (включая вас самих), чего достиг ваш код на каком-то этапе.
    Предположим, у вас есть список записей, и каждая из них может быть чистой (что хорошо) или это может быть smorsh, trale, gullup или twinkled (которые все неприемлемы).Если это сморш, то, должно быть, не сморщенный;если это трейл, то , должно быть, балудоед;если это чайка, то ее нужно пустить рысью (а затем, возможно, и шагом).;если он мерцает, он должен мерцать снова, за исключением четвергов.Вы уловили идею:Это сложная штука.Но конечным результатом является (или должно быть) то, что все записи чистые.Правильная вещь (TM), которую нужно сделать, это суммировать эффект вашего цикла очистки как

    assert(all(entry.isClean() for entry in mylist))
    

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

  4. Сообщите компьютеру, чего достиг ваш код в какой-то момент.
    Если вы забыли в ПАСЕ запись понадобится после бега в assert это спасет ваш день и позволит избежать того, что ваш код сломается гораздо позже, дорогая Дафни.

В моем сознании, assertдве цели документации (1 и 3) и защита (2 и 4) одинаково ценны.
Информирование людей может даже быть Еще ценнее, чем информирование компьютера потому что это может предотвратить те самые ошибки, которые assert стремится поймать (в случае 1) и множество последующих ошибок в любом случае.

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

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

class XLessThanZeroException(Exception):
    pass

def CheckX(x):
    if x < 0:
        raise XLessThanZeroException()

def foo(x):
    CheckX(x)
    #do stuff here

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

Как было сказано ранее, утверждения следует использовать, когда ваш код НИКОГДА НЕ ДОЛЖЕН достигать определенной точки, что означает наличие ошибки.Вероятно, самая полезная причина, которую я вижу для использования утверждения, - это инвариантное / предварительное / постусловие.Это то, что должно быть истинным в начале или конце каждой итерации цикла или функции.

Например, рекурсивная функция (2 отдельные функции, поэтому 1 обрабатывает неверный ввод, а другая обрабатывает неверный код, потому что его трудно отличить с помощью рекурсии).Это сделало бы очевидным, если бы я забыл написать оператор if, что пошло не так.

def SumToN(n):
    if n <= 0:
        raise ValueError, "N must be greater than or equal to 0"
    else:
        return RecursiveSum(n)

def RecursiveSum(n):
    #precondition: n >= 0
    assert(n >= 0)
    if n == 0:
        return 0
    return RecursiveSum(n - 1) + n
    #postcondition: returned sum of 1 to n

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

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

# I solemnly swear that here I will tell the truth, the whole truth, 
# and nothing but the truth, under pains and penalties of perjury, so help me FSM
assert answer == 42

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

Является есть проблема с производительностью?

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

  • Будьте прагматичны:
    Предположим, у вас есть метод, который обрабатывает непустой список кортежей, и логика программы нарушится, если эти кортежи не будут неизменяемыми.Вы должны написать:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))
    

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

    def mymethod(listOfTuples):
        assert(type(listOfTuples[0])==tuple)  # in fact _all_ must be tuples!
    

    который стоит дешево, но, скорее всего, уловит большую часть фактический ошибки программы в любом случае.

Есть фреймворк под названием JBoss Пускает слюни для java, которая выполняет мониторинг времени выполнения для утверждения бизнес-правил, что отвечает на вторую часть вашего вопроса.Однако я не уверен, существует ли такой фреймворк для python.

Утверждение заключается в проверке -
1.действительное условие,
2.действительное утверждение,
3.истинная логика;
исходного кода.Вместо того, чтобы провалить весь проект, он выдает сигнал тревоги о том, что в вашем исходном файле что-то не подходит.

В примере 1, поскольку переменная 'str' не равна nul.Таким образом, никаких утверждений или исключений не возникает.

Пример 1:

#!/usr/bin/python

str = 'hello Pyhton!'
strNull = 'string is Null'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
hello Pyhton!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py

В примере 2 var 'str' равен nul.Таким образом, мы спасаем пользователя от опережения неисправной программы, утверждать заявление.

Пример 2:

#!/usr/bin/python

str = ''
strNull = 'NULL String'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
AssertionError: NULL String

В тот момент, когда мы не хотим отлаживать и осознали проблему с утверждением в исходном коде.Отключите флаг оптимизации

python - O assertStatement.py
ничего не будет напечатано

В IDE, таких как PTVS, PyCharm, Wing assert isinstance() инструкции могут быть использованы для включения завершения кода для некоторых неясных объектов.

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

try:
    assert False
    raise Exception('Python Assertions are not working. This tool relies on Python Assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
    pass
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top