Безопасно ли полагаться на порядок оценки условий в операторах if? - PullRequest
62 голосов
/ 15 апреля 2009

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

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 (если есть)?

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

Ответы [ 6 ]

82 голосов
/ 15 апреля 2009

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

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

IF exists(variable) AND variable.doSomething()
    THEN ...
31 голосов
/ 15 апреля 2009

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

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

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

2 голосов
/ 01 сентября 2009

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

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 используется для указания аргумента функции по умолчанию.

1 голос
/ 05 июня 2009

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

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 минут (слишком долго), поэтому парни из C # (и других) должны быть очень осторожны при кодировании на других языках.

1 голос
/ 15 апреля 2009

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

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

1 голос
/ 15 апреля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...