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