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