Странная рекомендация PEP8 при сравнении булевых значений с True или False

в конце 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 и что для этих переменных не следует избегать ?

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

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

5 ответов


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

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

в ОПТОСОЗ говорится, что все, что он содержит рекомендации. Есть исключения правила и этот ничем не отличается.


Я считаю, что вы ошибаетесь. Постарайтесь не думать о 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)

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

if (isComplete == True) ...
if ((isComplete == True) == True) ...
if (((isComplete == True) == True) == True) ...
if ((((isComplete == True) == True) == True) == True)...

Это часть duck typing. В 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 приведет к тому, что это не сработает.

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


простейшая причина не сравнивать истину через == или != сравнения, кажется, это:

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 не будет ли это оценивает to 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 на личность, но и использовать == на равенство.

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

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


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

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