Странная рекомендация PEP8 при сравнении логических значений с True или False - PullRequest
14 голосов
/ 29 октября 2010

В конце Python PEP8 Я читаю:

  • Не сравнивайте логические значения с True или False, используя ==

    Yes:   if greeting:
    No:    if greeting == True:
    Worse: if greeting is True:
    

У меня нет проблем с этой рекомендацией, когда логическое значение равно True, но это звучит странно при проверке False

Если я хочу знать, является ли приветствие переменнойНеверно, почему я не должен писать:

    if greeting == False:

Если я напишу if not greeting:, это будет иметь совсем другое значение, чем приведенное выше утверждение.Что делать, если приветствие Нет?Что если это пустая строка?Означает ли эта рекомендация PEP8, что переменные, хранящие логические значения, должны содержать только True или False и что для этих переменных следует избегать None?

На мой взгляд, это выглядит как рекомендация, исходящая из других языков со статической типизацией, и это делаетне подходит для Python, по крайней мере, для сравнения с False.

И, кстати, кто-нибудь знает, почему if greeting is True: описывается как хуже, чем if greeting == True:?Должны ли мы также понимать, что if greeting is False: также хуже, чем if greeting == False:?

Ответы [ 5 ]

16 голосов
/ 29 октября 2010

Я полагаю, что вы читаете это неправильно. Старайтесь не думать о greeting как о существительном, а как о глаголе («Я приветствую» вместо «Это приветствие»).

Вы можете увидеть подсказку в преамбуле к PEP8:

Одним из ключевых выводов Гвидо является то, что код читается гораздо чаще, чем пишется. Приведенные здесь рекомендации предназначены для улучшения читабельности кода.

Для этого код должен максимально напоминать письменное или устное слово. Вы не говорите "If I am annoying you is true, let me know" в реальной жизни, вы просто говорите "If I am annoying you, let me know".

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

Вы никогда не должны делать что-то вроде:

if (isOpen == True)

или

if (customerDead == False)

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

if (isComplete == True) ...
if ((isComplete == True) == True) ...
if (((isComplete == True) == True) == True) ...
if ((((isComplete == True) == True) == True) == True)...
5 голосов
/ 30 апреля 2015

Простейшая причина не сравнивать правду с помощью == или != сравнений выглядит так:

0 is False # Result: False
0 == False # Result: True; 0 evaluates comparatively to False

1 is True  # Result: False  
1 == True  # Result: True; 1 evaluates comparatively to True

is проверяет, является ли переданное значение точно True / False, не имеет значения от до True или False.

Такое поведение позволяет это:

if var is False:
   # False (bool) case
elif var is None:
   # None case
elif var == 0:
   # integer 0 case

, тогда как

if var == False:
    # catches False & 0 case; but not None case, empty string case, etc.

, что кажется нелогичным - вот почему я ожидаю, что PEP8 говорит: «не делайте этого»».

Как сказано здесь используйте is для идентичности , но используйте == для равенства .

You 'я хочу использовать if var is True только когда вам нужно значение bool True, но вы хотите отклонить 1, 'some string' и т. д.

Такие случаи, вероятно, не очевидны для большинства читателей;Я подозреваю, что PEP8 утверждает, что это «хуже», потому что оно потенциально вводит в заблуждение.Время от времени это может быть необходимым злом;но ... если вам понадобится is True, может указывать на проблему с дизайном.В любом случае, вы, вероятно, должны прокомментировать «почему», вам нужно точно True или False, если вы когда-либо используете is.

5 голосов
/ 29 октября 2010

Это часть утки. В Python вы обычно не хотите ограничивать то, что вы принимаете, конкретным классом, но объектом, который предоставляет надлежащий API. Например, я могу сделать это:

class MyProperty(object):
    """
    A file-backed boolean property.
    """
    def __init__(self, filename):
        self.value = open(filename).read()
    def __nonzero__(self):
        return self.value != "0"
    def save_to_disk(self):
        # ... and so on
        pass

def func(enabled):
    if not enabled:
        return
    # ...

enable_feature = MyProperty("enable_feature")
func(enable_feature)

Если сказать if enabled == False, это не сработает.

Ложь - это a ложное значение, но это не только только ложное значение. Избегайте сравнения с True и False по той же причине, по которой вы избегаете использовать isinstance.

1 голос
/ 29 октября 2010

Насколько я понимаю, рекомендация PEP подразумевает, что, если вы знаете, что можете быть достаточно уверены в типе foo (что обычно имеет место), тогда тестирование явного ложного значения является излишним и снижает читабельность. Например, в foo = [i for i in range(10) if i == x] вы можете быть совершенно уверены, что единственное ложное значение, которое может иметь foo, это [] (при условии, что исключений не возникает). В этом случае избыточно использовать foo == [], а not foo лучше.

С другой стороны, семантическое значение foo == [] или foo == False иногда более ценно, и тогда должен использоваться (IMHO) вместо not foo. Это зависит от того, что конкретно вы пытаетесь общаться. Фактически not foo означает"foo имеет a ложное значение?", Тогда как foo == False означает"foo имеет то же значение, что и False?».

PEP заявляет, что все, что он содержит, является руководящими принципами . Есть исключения из правил, и это ничем не отличается.

0 голосов
/ 29 октября 2010

Я обычно называю свои логические переменные после шаблона IsName, поэтому в вашем случае IsGreeting. Это заставляет чек читать if IsGreeting / if not IsGreeting, что очень интуитивно понятно.

Неопределенности, которые вы описываете с помощью if not, являются результатом использования не булевых типов в булевых сравнениях. Этого обычно следует избегать, так как это очень запутанно.

...