Чи безпечно покладатися на порядок оцінки стану у твердженнях if?


77

Чи погана практика використовувати наступний формат, коли 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 (якщо така є)?

Ласкаво просимо!

Відповіді:


94

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

Цей тип коду з’являється на більшості мов:

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

3
Коли я бачу код, подібний до другого, я припускаю, що кодер не зрозумів, як працює оцінка короткого замикання.
Дана

1
-1: Цитата з документації відсутня
S.Lott

@cfi: Оскільки я можу змінити свій голос після зміни відповіді, мені незрозуміло, в чому проблема.
S.Lott

@cfi: Робіть те, що, на вашу думку, є найціннішим для інших. Моя оцінка -1 щодо коментаря не пов'язана з моїм фактичним голосуванням. Цікаво, що це дозволяє зробити тривале зауваження, не пов’язане з фактичною цінністю відповіді.
S.Lott

1
для всіх, хто налаштований негативно, це слушне запитання і не однакове для кожної мови. VB оцінить і те, і інше, якщо ви не використаєте andalsoабоorelse
blindguy

35

Так, це безпечно, це чітко і дуже чітко визначено в мовному посиланні:

Вираз x and yспочатку оцінює x; якщо xє false, повертається його значення; в іншому випадку yобчислюється і отримане значення повертається.

Вираз x or yспочатку оцінює x; якщо xtrue, повертається його значення; в іншому випадку yобчислюється і отримане значення повертається.


1
Слабкий: це не "безпечно" - це абсолютно потрібно, щоб залежати від замовлення.
S.Lott

4

Можливо, я тут трохи педантичний, але я б сказав, що найкраща відповідь

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


безумовно, якщо у вас є порожній список або будь-який контейнер, з цього приводу робити inоперацію безглуздо. Я думаю, що ОП це правильно. хоча можливо побудувати що завгодно, щоб довести свою думку, я не вірю, що будь-який пристойний код повинен стріляти собі в ногу.
SilentGhost

1
Так, це надуманий приклад, але моя головна думка полягає в тому, що легко увійти в шкідливу звичку говорити ` if var` коли ти маєш на увазі ' if var is not None'. Після того, як ви увійдете в цю звичку, він може легко вас вкусити, особливо аргументами за замовчуванням.
Скотт Гріффітс,

Я думаю, цілком зрозуміло, що наміром ОП було сказати, if varі це він зробив.
SilentGhost

3

Це не так просто. Як чувак 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

Я хотів би спробувати / виключити, але це залежить від того, що ви знаєте про змінну.

Якщо ви очікуєте, що змінна буде існувати більшу частину часу, тоді спроба / крім менше операцій. Якщо ви очікуєте, що змінна більшу частину часу матиме значення None, тоді оператор IF матиме менше операцій.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.