Можно ли полагаться на порядок оценки условий в операторах 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 (если есть)?
Альтернативы приветствуются!
Ответы
Ответ 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 минут (слишком долго), и поэтому С# (и другие) парни должны быть очень осторожны при кодировании на других языках.