Подтвердить что ты не робот

Можно ли полагаться на порядок оценки условий в операторах if?

Неправильная практика использовать следующий формат, если my_var может быть None?

if my_var and 'something' in my_var:
    #do something

Проблема в том, что 'something' in my_var будет генерировать TypeError, если my_var - None.

Или я должен использовать:

if my_var:
    if 'something' in my_var:
        #do something

или

try:
    if 'something' in my_var:
        #do something
except TypeError:
    pass

Чтобы перефразировать вопрос, какой из вышеперечисленных является наилучшей практикой в ​​Python (если есть)?

Альтернативы приветствуются!

4b9b3361

Ответ 1

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

Этот тип кода появляется на большинстве языков:

IF exists(variable) AND variable.doSomething()
    THEN ...

Ответ 2

Да, это безопасно, оно явно и очень четко определено в языковой ссылке:

Выражение x and y сначала оценивает x; если x false, то его значение равно вернулся; в противном случае y оценивается и полученное значение возвращается.

Выражение x or y сначала оценивает x; если x истинно, его значение равно вернулся; в противном случае y оценивается и полученное значение возвращается.

Ответ 3

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

if my_var is not None and 'something' in my_var:
    #do something

Разница заключается в явной проверке для None, а не на неявном преобразовании my_var в True или False.

Хотя я уверен, что в вашем случае различие не важно, в более общем случае было бы вполне возможно, что переменная не будет None, но все равно будет оцениваться до False, например целочисленное значение из 0 или пустой список.

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

class Contrived(object):
    def __contains__(self, s):
        return True
    def __nonzero__(self):
        return False

my_var = Contrived()
if 'something' in my_var:
    print "Yes the condition is true"
if my_var and 'something' in my_var:
    print "But this statement won't get reached."
if my_var is not None and 'something' in my_var:
    print "Whereas this one will."

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

Ответ 4

Это абсолютно безопасно, и я делаю это все время.

Ответ 5

Я бы пошел с try/except, но это зависит от того, что вы знаете о переменной.

Если вы ожидаете, что переменная будет существовать большую часть времени, тогда try/except меньше операций. Если вы ожидаете, что переменная будет больше неактивной, тогда оператор IF будет меньше операций.

Ответ 6

Это не так просто. Как чувак С# я очень привык делать что-то вроде:

if(x != null && ! string.isnullorempty(x.Name))
{
   //do something
}

Вышеизложенное отлично работает и оценивается как ожидалось. Однако в VB.Net следующее приведет к результату, которого вы НЕ ожидали:

If Not x Is Nothing **And** Not String.IsNullOrEmpty(x.Name) Then

   'do something

End If

Вышеизложенное генерирует исключение. Правильный синтаксис должен быть

If Not x Is Nothing **AndAlso** Not String.IsNullOrEmpty(x.Name) Then

   'do something

End If

Обратите внимание на очень тонкую разницу. Это меня смутило около 10 минут (слишком долго), и поэтому С# (и другие) парни должны быть очень осторожны при кодировании на других языках.