Использование True, False и None в качестве возвращаемых значений в функциях python
Я думаю, что я полностью понимаю это, но я просто хочу убедиться, так как я продолжаю видеть, как люди говорят никогда не тестировать против True
, False
или None
. Они предполагают, что подпрограммы должны вызывать ошибку, а не возвращать False или None. Во всяком случае, у меня есть много ситуаций, когда я просто хочу знать, установлен ли флаг или нет, поэтому моя функция возвращает True или False. Есть и другие ситуации, когда у меня есть функция return None, если не было полезного результата. Из моего мышления, ни проблематично, пока я понимаю, что я никогда не должен использовать:
if foo == True
if foo == False
if foo == None
и вместо него следует использовать:
if foo is True
if foo is False
if foo is None
поскольку True, False и None - все синглеты и всегда будут оценивать так, как я ожидаю при использовании "is", а не "==". Я ошибаюсь?
наряду с этим, было бы более подходящие для Python, чтобы изменить функции, иногда нет, так что они вместо того, чтобы вызвать ошибку? Скажем, у меня есть метод экземпляра под названием "get_attr ()", который извлекает атрибут из какого-то файла. В случае, когда он обнаруживает, что запрошенный атрибут не существует, целесообразно ли возвращать None? Было бы лучше, если бы они подняли ошибку и поймали ее позже?
9 ответов
совет не в том, что вы никогда не должны использовать True
, False
или None
. Это просто, что вы не должны использовать if x == True
.
if x == True
- это глупо, потому что ==
это просто двоичный оператор! Он имеет возвращаемое значение либо True
или False
, в зависимости от того, равны ли его аргументы или нет. И if condition
будет продолжена, если condition
- это правда. Поэтому, когда вы пишете if x == True
Python собирается сначала оценить x == True
, который станет True
Если x
был True
и False
в противном случае, а затем, если результат это верно. Но если вы ожидаете x
либо True
или False
, Почему бы просто не использовать if x
напрямую!
кроме того, x == False
обычно можно заменить на not x
.
есть некоторые обстоятельства, где вы можете использовать x == True
. Это потому что if
условие оператора "оценивается в булевом контексте", чтобы увидеть, является ли оно" истинным", а не тестируется точно против True
. Например, непустые строки, списки и словари считаются истинными оператором if, а также ненулевые числовые значения, но ни одно из них не равно True
. Поэтому, если вы хотите проверить, является ли произвольное значение ровно значение True
не только ли это истина, когда вы будете использовать if x == True
. Но я почти никогда не вижу в этом смысла. Это так редко, что если вы do когда-либо нужно написать это, стоит добавить комментарий Так будущее разработчики (включая, возможно, вас) не просто предполагают == True
лишнее и удалить его.
используя x is True
вместо этого на самом деле хуже. Вы никогда не должны использовать is
базовый встроенный неизменяемые типы как логические (True
, False
), числа и строки. Причина в том, что для этих типов мы заботимся о значения, а не личность. ==
тесты, что значения одинаковы для этих типов, в то время как is
всегда тесты Identities.
тестирование идентификаторов, а не значений плохо, потому что реализация теоретически может создавать новые логические значения, а не находить существующие, что приводит к тому, что у вас есть два True
значения, которые имеют одно и то же значение, но хранятся в разных местах в памяти и имеют разные идентификаторы. На практике я почти уверен True
и False
всегда повторно используются интерпретатором Python, поэтому этого не произойдет, но это действительно деталь реализации. Этот проблема заставляет людей все время работать со строками, потому что короткие строки и литеральные строки, которые появляются непосредственно в источнике программы, перерабатываются Python so 'foo' is 'foo'
всегда возвращает True
. Но легко построить одну и ту же строку 2 разными способами и заставить Python дать им разные идентификаторы. Наблюдаем следующее:
>>> stars1 = ''.join('*' for _ in xrange(100))
>>> stars2 = '*' * 100
>>> stars1 is stars2
False
>>> stars1 == stars2
True
EDIT: Итак, оказывается, что равенство Python на булевых немного неожиданное (по крайней мере, для me):
>>> True is 1
False
>>> True == 1
True
>>> True == 2
False
>>> False is 0
False
>>> False == 0
True
>>> False == 0.0
True
обоснование этого, как объясняется в заметки, когда bools были введены в Python 2.3.5, что старое поведение использования целых чисел 1 и 0 для представления True и False было хорошим, но мы просто хотели больше описательных имен для чисел, которые мы намеревались представить значения истины.
один из способов добиться этого - просто иметь True = 1
и False = 0
в builtins; тогда 1 и True действительно были бы неразличимы (включая is
). Но это также означает, что функция returning True
покажет 1
в интерактивном интерпретаторе, так что вместо этого было сделано, чтобы создать bool
как подтип int
. Единственное, что отличается от bool
is str
и repr
; bool
экземпляры по-прежнему имеют те же данные, что и int
экземпляры, и все равно сравнить равенство таким же образом, так что True == 1
.
поэтому неправильно использовать x is True
, когда x
возможно, был установлен по некоторому коду, который ожидает, что "True - это просто еще один способ написания 1", потому что есть много способов построить значения, равные True
но не имеют такой же идентификатор, как это:
>>> a = 1L
>>> b = 1L
>>> c = 1
>>> d = 1.0
>>> a == True, b == True, c == True, d == True
(True, True, True, True)
>>> a is b, a is c, a is d, c is d
(False, False, False, False)
и неправильно использовать x == True
, когда x
может быть произвольным значением Python, и вы только хотите знать, является ли это логическим значением True
. Единственная уверенность в том, что мы просто используем x
лучше всего, когда вы просто хотите проверить "правдивость". К счастью, это обычно все, что требуется, хотя бы в коде пишу!
более уверенным способом было бы x == True and type(x) is bool
. Но это становится довольно многословным для довольно неясного дела. Он также не очень подходящие для Python, делая явной проверки типа... но это действительно то, что вы делаете, когда пытаетесь проверить точно True
вместо truthy; способ ввода утки будет принимать истинные значения и позволять любому определяемому пользователем классу объявлять себя истинным.
если вы имея дело с этим чрезвычайно точным понятием истины, где вы не только не считаете непустые коллекции истинными, но и не считаете 1 истинным, а затем просто используете x is True
вероятно, все в порядке, потому что предположительно тогда вы знаете, что x
не из кода, который считает 1 истинным. Я не думаю, что есть какой-либо способ чистого питона придумать другой True
который живет на другом адресе памяти (хотя вы, вероятно, могли бы сделать это из C), поэтому это никогда не должно сломаться, несмотря на быть теоретически "неправильным" поступком.
и я привык думать, что булевы были простыми!
End Edit
в случае None
, однако, идиома заключается в использовании if x is None
. Во многих случаях вы можете использовать if not x
, потому что None
является значением "falsey" для if
заявление. Но лучше всего делать это, только если вы хотите обработать все значения falsey (нулевые числовые типы, пустые коллекции и None
) в так же. Если вы имеете дело со значением, которое является либо некоторым возможным другим значением, либо None
чтобы указать "нет значения" (например, когда функция возвращает None
при сбое), то это много лучше использовать if x is None
чтобы вы случайно не предположили, что функция не удалась, когда она просто возвращала пустой список или число 0.
мои аргументы за использование ==
, а не is
для неизменяемых типов значений рекомендуется использовать if x == None
а не if x is None
. Однако, в случае None
Python явно гарантирует, что существует ровно один None
во всей Вселенной, и нормальный идиоматический код Python использует is
.
относительно того, возвращаться ли None
или вызвать исключение, это зависит от контекста.
для чего-то вроде вашего get_attr
пример я ожидал бы, что он вызовет исключение, потому что я буду называть его как do_something_with(get_attr(file))
. Нормальное ожидание вызывающие абоненты - это то, что они получат значение атрибута и получат None
и предположим, что значение атрибута намного хуже, чем забыть обработать исключение, когда вы действительно можете продолжить, если атрибут не может быть найден. Плюс, возвращение None
, чтобы указать отказ означает, что None
недопустимое значение атрибута. В некоторых случаях это может быть проблемой.
для мнимой функции, такой как see_if_matching_file_exists
, что мы предоставляем шаблон, и он проверяет несколько места, чтобы увидеть, есть ли совпадение, он может вернуть совпадение, если найдет его или None
если это не так. Но в качестве альтернативы он может вернуть список совпадений; тогда никакое совпадение не является просто пустым списком (который также "фальсифицирован"; это одна из тех ситуаций, когда я просто использую if x
чтобы узнать, получил ли я что-нибудь обратно).
поэтому при выборе между исключениями и None
чтобы указать на неудачу, вы должны решить, является ли None
является ожидаемым значением отказа, а затем посмотрите на ожидания кода, вызывающего функцию. Если "нормальное" ожидание заключается в том, что будет возвращено допустимое значение, и только иногда вызывающий абонент сможет нормально работать независимо от того, возвращено ли допустимое значение, вы должны использовать исключения для указания на сбой. Если это будет довольно распространено, чтобы не было допустимого значения, поэтому абоненты будут ожидать обработки обеих возможностей, тогда вы можете использовать None
.
использовать if foo
или if not foo
, нет необходимости в либо ==
или is
для этого.
для проверки против None,is None
и есть. Это позволяет отличить его от False (или вещей, которые оцениваются как False, например ""
и []
).
ли get_attr
должен возвратить None
будет зависеть от контекста. У вас может быть атрибут, где значение равно None, и вы не сможете этого сделать. Я бы истолковал None
as значение "отключено", и KeyError
будет означать, что ключ не существует в файле.
если проверка на правдивость:
if foo
для false:
if not foo
нет:
if foo is None
для non-none:
if foo is not None
на getattr()
правильное поведение-это не вернуться None
но поднять AttributError
ошибка вместо этого-если ваш класс не что-то вроде defaultdict
относительно того, следует ли создавать исключение или возвращать None
: Это зависит от варианта использования. Или может быть обновления. Посмотрите на python dict
например класс x[y]
до dict.__getitem__
и он поднимает KeyError
если ключ отсутствует. Но!--8--> метод возвращает второй аргумент (который по умолчанию None
), если ключа нет. они оба полезны.
самая важная вещь, котор нужно рассматривать документировать это поведение в docstring, и убедитесь, что ваш get_attr()
метод делает то, что он говорит, он делает.
чтобы ответить на другие ваши вопросы, используйте следующие соглашения:
if foo:
# for testing truthiness
if not foo:
# for testing falsiness
if foo is None:
# testing .. Noneliness ?
if foo is not None:
# check explicitly avoids common bugs caused by empty sequences being false
функции, которые возвращают True
или False
вероятно, должно иметь имя, которое делает это очевидным для улучшения читаемости кода
def is_running_on_windows():
return os.name == 'nt'
в python3 вы можете "ввести подсказку", что:
>>> def is_running_on_windows() -> bool:
... return os.name == 'nt'
...
>>> is_running_on_windows.__annotations__
{'return': bool}
Вы можете непосредственно проверить, что переменная содержит значение или не нравится if var
или not var
.
в примерах PEP 8(руководство по стилю для кода Python) документ, Я видел, что foo is None
или foo is not None
используются вместо foo == None
или foo != None
. Также используя if boolean_value
рекомендуется в этом документе вместо if boolean_value == True
или if boolean_value is True
. Поэтому я думаю, что если это официальный путь Python, мы, ребята Python, тоже должны идти этим путем.
С уважением.
в случае вашего вымышленного getattr
function, если запрошенный атрибут всегда должен быть доступен, но затем не выдает ошибку. Если атрибут является необязательным, то return None
.
одна вещь, чтобы гарантировать, что ничто не может переназначить вашу переменную. Если он не является логическим в конце концов, полагаясь на правдивость приведет к ошибкам. Красота условного программирования на динамически типизированных языках :).
следующие отпечатки "нет".
x = False
if x:
print 'yes'
else:
print 'no'
теперь давайте изменим x.
x = 'False'
теперь заявление принтами "да " потому что строка правдива.
if x:
print 'yes'
else:
print 'no'
такое заявление, однако правильно выводит"нет".
if x == True:
print 'yes'
else:
print 'no'