нулевой объект в Python?

1194

Как мне обратиться к нулевому объекту в Python?

ящерица
источник

Ответы:

1630

В Python объект 'null' является синглтоном None.

Лучший способ проверить вещи на «Noneness» - это использовать оператор идентификации is:

if foo is None:
    ...
Бен Джеймс
источник
126
И причина выбора egg is Noneболее egg == None: Последние могут быть перегружены, и, вероятно, ломаются при сравнении действительного объекта None (зависит от того, как это реализовано, но не ожидает , что все взять сравнения с None во внимание, не так ли?) , при этом isвсегда работает одинаково.
94
почему разработчики Python просто не выбрали «ноль». Просто должен быть другим, не так ли? ;)
Видар
35
@ Vidar «None» - это не отсутствие объекта (как и «null», нулевая ссылка), это фактический объект. Вы никогда не получите объект None, передающий объект, который относится к какому-либо типу, отличному от NoneType. Это также не концепция языка. Она не встроена в язык Python, она является частью стандартной библиотеки Python. Нет! == (Гм) Null
Rushyo
11
@ naught101 Это бесполезно; так как нет понятия указателей. Если вы используете библиотеку ctypes, None будет использоваться в качестве синонима для нулевого адреса, но до сих пор нет языковой концепции «нулевой ссылки». В Python вы всегда оставляете ссылку на какой-либо объект, даже если этот объект имеет значение None. Я подозреваю, что это значительно упрощает язык.
Rushyo
5
отличная презентация, объясняющая «ошибку в миллиард долларов», которая является нулевым ref: infoq.com/presentations/… . Другими параметрами, отличными от null, являются Options или Maybe (custom) типы.
Майкл Троу
136

None, Питон ноль?

Там нет nullв Python, а есть None. Как уже говорилось, наиболее точный способ проверить, что что-то задано Noneв качестве значения, - это использовать isоператор тождества, который проверяет, что две переменные ссылаются на один и тот же объект.

>>> foo is None
True
>>> foo = 'bar' 
>>> foo is None
False

Основы

Есть и может быть только один None

Noneявляется единственным экземпляром класса, NoneTypeи любые дальнейшие попытки создания экземпляра этого класса будут возвращать тот же объект, который создает Noneодиночный объект . Новички в Python часто видят сообщения об ошибках, которые упоминают NoneTypeи задаются вопросом, что это такое. По моему личному мнению, эти сообщения можно просто назвать Noneпо имени, потому что, как мы скоро увидим, Noneмало места для неопределенности. Поэтому, если вы видите какое-то TypeErrorсообщение, в котором упоминается, что NoneTypeэто не может или не может, просто знайте, что это просто то None, что использовалось таким образом, что это невозможно.

Кроме того, Noneэто встроенная константа, и как только вы запускаете Python, ее можно использовать везде, будь то в модуле, классе или функции. NoneTypeнапротив, нет, вам нужно сначала получить ссылку на него, запросив Noneего класс.

>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType

Вы можете проверить Noneуникальность с помощью функции идентичности Python id(). Он возвращает уникальный номер, присвоенный объекту, каждый объект имеет один. Если id двух переменных одинаков, то они фактически указывают на один и тот же объект.

>>> NoneType = type(None)
>>> id(None)
10748000
>>> my_none = NoneType()
>>> id(my_none)
10748000
>>> another_none = NoneType()
>>> id(another_none)
10748000
>>> def function_that_does_nothing(): pass
>>> return_value = function_that_does_nothing()
>>> id(return_value)
10748000

None не может быть перезаписано

В гораздо более старой версии Python (до 2.4) можно было переназначить None, но не больше. Даже в качестве атрибута класса или в пределах функции.

# In Python 2.7
>>> class SomeClass(object):
...     def my_fnc(self):
...             self.None = 'foo'
SyntaxError: cannot assign to None
>>> def my_fnc():
        None = 'foo'
SyntaxError: cannot assign to None

# In Python 3.5
>>> class SomeClass:
...     def my_fnc(self):
...             self.None = 'foo'
SyntaxError: invalid syntax
>>> def my_fnc():
        None = 'foo'
SyntaxError: cannot assign to keyword

Поэтому можно с уверенностью предположить, что все Noneссылки одинаковы. Там нет "обычай" None.

Для проверки на Noneиспользование isоператором

При написании кода у вас может возникнуть соблазн проверить на Единое, как это:

if value==None:
    pass

Или проверить на ложь, как это

if not value:
    pass

Вы должны понимать последствия и то, почему это часто хорошая идея, чтобы быть явным.

Случай 1: проверка, если значение None

зачем это

value is None

скорее, чем

value==None

Первый эквивалентен:

id(value)==id(None)

В то время как выражение value==Noneна самом деле применяется так

value.__eq__(None)

если значение действительно так, Noneто вы получите то, что ожидали.

>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True

В большинстве распространенных случаев результат будет таким же, но __eq__()метод открывает дверь, которая аннулирует любую гарантию точности, так как она может быть переопределена в классе для обеспечения особого поведения.

Рассмотрим этот класс.

>>> class Empty(object):
...     def __eq__(self, other):
...         return not other

Таким образом, вы примеряете, Noneи это работает

>>> empty = Empty()
>>> empty==None
True

Но тогда это также работает на пустой строке

>>> empty==''
True

И все еще

>>> ''==None
False
>>> empty is None
False

Случай 2: Использование Noneв качестве логического значения

Следующие два теста

if value:
    # do something

if not value:
    # do something

на самом деле оцениваются как

if bool(value):
    # do something

if not bool(value):
    # do something

Noneявляется "ложным", означающим, что если приведен к логическому значению, он вернется, Falseа если применяется notоператор, он вернется True. Обратите внимание, что это не уникальное свойство None. В дополнение к Falseсамому себе, свойство совместно используется пустыми списками, кортежами, наборами, комментариями, строками, а также 0 и всеми объектами из классов, которые реализуют __bool__()возвращаемый магический метод False.

>>> bool(None)
False
>>> not None
True

>>> bool([])
False
>>> not []
True

>>> class MyFalsey(object):
...     def __bool__(self):
...         return False
>>> f = MyFalsey()
>>> bool(f)
False
>>> not f
True

Поэтому при тестировании переменных следующим образом, будьте особенно внимательны к тому, что вы включаете или исключаете из теста:

def some_function(value=None):
    if not value:
        value = init_value()

Выше вы хотели вызывать, init_value()когда значение установлено специально None, или вы имели в виду, что значение 0, или пустая строка, или пустой список также должны инициировать инициализацию. Как я уже сказал, будьте внимательны. Как это часто бывает в Python, явное лучше, чем неявное .

None на практике

None используется в качестве значения сигнала

Noneимеет особый статус в Python. Это любимое базовое значение, потому что многие алгоритмы рассматривают его как исключительное значение. В таких сценариях его можно использовать в качестве флага для обозначения того, что условие требует некоторой специальной обработки (например, установка значения по умолчанию).

Вы можете присвоить Noneключевым словам аргументы функции, а затем явно проверить ее.

def my_function(value, param=None):
    if param is None:
        # do something outrageous!

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

value = getattr(some_obj, 'some_attribute', None)
if value is None:
    # do something spectacular!

По умолчанию get()метод словаря возвращается Noneпри попытке доступа к несуществующему ключу:

>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True

Если бы вы попытались получить к нему доступ, используя нижнюю нотацию, KeyErrorбыло бы поднято

>>> value = some_dict['foo']
KeyError: 'foo'

Точно так же, если вы пытаетесь вставить несуществующий элемент

>>> value = some_dict.pop('foo')
KeyError: 'foo'

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

value = some_dict.pop('foo', None)
if value is None:
    # booom!

None используется как флаг и действительное значение

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

Когда вы запрашиваете у объекта его атрибут с getattr(some_obj, 'attribute_name', None)возвратом, Noneон не сообщает вам, был ли установлен атрибут, к которому вы пытались получить доступ, Noneили он вообще отсутствовал в объекте. Та же самая ситуация при доступе к ключу из словаря, например some_dict.get('some_key'), вы не знаете, some_dict['some_key']отсутствует ли или просто установлен None. Если вам нужна эта информация, обычный способ справиться с этим - попытаться напрямую получить доступ к атрибуту или ключу из try/exceptконструкции:

try:
    # equivalent to getattr() without specifying a default
    # value = getattr(some_obj, 'some_attribute')
    value = some_obj.some_attribute
    # now you handle `None` the data here
    if value is None:
        # do something here because the attribute was set to None
except AttributeError:
    # we're now hanling the exceptional situation from here.
    # We could assign None as a default value if required.
    value = None 
    # In addition, since we now know that some_obj doesn't have the
    # attribute 'some_attribute' we could do something about that.
    log_something(some_obj)

Аналогично с dict:

try:
    value = some_dict['some_key']
    if value is None:
        # do something here because 'some_key' is set to None
except KeyError:
    # set a default 
    value = None
    # and do something because 'some_key' was missing
    # from the dict.
    log_something(some_dict)

Два приведенных выше примера показывают, как обращаться с объектами и словарями, а как насчет функций? То же самое, но мы используем аргумент ключевого слова с двумя звездочками для этой цели:

def my_function(**kwargs):
    try:
        value = kwargs['some_key'] 
        if value is None:
            # do something because 'some_key' is explicitly 
            # set to None
    except KeyError:
        # we assign the default
        value = None
        # and since it's not coming from the caller.
        log_something('did not receive "some_key"')

None используется только как действительное значение

Если вы обнаружите, что ваш код завален вышеуказанным try/exceptшаблоном, чтобы просто различать Noneфлаги и Noneданные, просто используйте другое тестовое значение. Существует шаблон, в котором значение, которое выходит за пределы набора допустимых значений, вставляется как часть данных в структуру данных и используется для контроля и проверки особых условий (например, границ, состояния и т. Д.). Такое значение называется часовым, и его можно использовать так Noneже, как в качестве сигнала. Создание часового в Python тривиально.

undefined = object()

Приведенный undefinedвыше объект является уникальным и не делает ничего из того, что может представлять интерес для программы, поэтому он является отличной заменой Noneфлага. Применяются некоторые предостережения, подробнее об этом после кода.

С функцией

def my_function(value, param1=undefined, param2=undefined):
    if param1 is undefined:
        # we know nothing was passed to it, not even None
        log_something('param1 was missing')
        param1 = None


    if param2 is undefined:
        # we got nothing here either
        log_something('param2 was missing')
        param2 = None

С диктом

value = some_dict.get('some_key', undefined)
if value is None:
    log_something("'some_key' was set to None")

if value is undefined:
    # we know that the dict didn't have 'some_key'
    log_something("'some_key' was not set at all")
    value = None

С объектом

value = getattr(obj, 'some_attribute', undefined) 
if value is None:
    log_something("'obj.some_attribute' was set to None")
if value is undefined:
    # we know that there's no obj.some_attribute
    log_something("no 'some_attribute' set on obj")
    value = None

Как я упоминал ранее, таможенные стражи идут с некоторыми оговорками. Во-первых, они не похожи на ключевые слова None, поэтому python их не защищает. Вы можете перезаписать undefinedвышеизложенное в любое время, в любом месте модуля, в котором он определен, поэтому будьте осторожны с тем, как вы его используете и используете. Далее, экземпляр, возвращаемый object()не одноэлементным, если вы сделаете этот вызов 10 раз, вы получите 10 различных объектов. Наконец, использование часового очень своеобразно. Часовой характерен для библиотеки, в которой он используется, и поэтому его область действия обычно должна быть ограничена внутренними компонентами библиотеки. Это не должно "вытекать" наружу. Внешний код должен узнавать об этом только в том случае, если их целью является расширение или дополнение API библиотеки.

Майкл Экока
источник
Как насчет: нет == вещь?
августа
@hkBst Я предполагаю, что ваш вопрос о том, как python оценивает равенство. Взгляните на этот stackoverflow.com/questions/3588776/…
Майкл Экока
Ах, так что IIUC, который обычно все равно будет звонить .__ eq__? В этом случае я отказываюсь от своего предложения.
hkBst
@MichaelEkoka вы можете поделиться источником этой впечатляющей и полезной информации.
Анидхья Бхатнагар
Общепринятая практика. Вы можете найти некоторые намеки на это , ознакомившись с руководством по Python , но чтение исходного кода популярных проектов - это мой совет номер один, чтобы быстро погрузиться в идиоматический Python .
Майкл
67

Это не называется нулевым, как на других языках, но None. Всегда есть только один экземпляр этого объекта, так что вы можете проверить эквивалентность с помощью x is None(сравнения идентификаторов) вместо x == None, если хотите.

AndiDog
источник
25
Я собираюсь найти способ сломать Python путем повторного создания экземпляра None. Тогда победят все умные люди, которые сравнивают друг с NoneTypeдругом!
Zenexer
28

В Python для представления отсутствия значения вы можете использовать значение None ( types.NoneType.None ) для объектов и "" (или len () == 0 ) для строк. Следовательно:

if yourObject is None:  # if yourObject == None:
    ...

if yourString == "":  # if yourString.len() == 0:
    ...

Что касается разницы между "==" и "is", проверки на идентичность объекта с использованием "==" должно быть достаточно. Однако, поскольку операция «is» определяется как операция идентификации объекта, вероятно, более правильно использовать ее, а не «==». Не уверен, что есть даже разница в скорости.

В любом случае, вы можете взглянуть на:

Паоло Ровелли
источник
8
Насколько я знаю, (0 == false) возвращает истину на КАЖДОМ языке программирования. Это потому, что false кодируется как 0, а «true» - как все, что НЕ 0. Однако, пожалуйста, обратите внимание, что оператор «is» не совпадает с оператором «==». Это более или менее одинаковая разница между "==" и "равно" в Java. Оператор «is» действительно проверяет, являются ли ДВА ОБЪЕКТА одинаковыми (один и тот же экземпляр, а НЕ одно и то же содержимое)!
Паоло Ровелли
12
Paolo, FYI, (0 == false) не возвращает true во всех языках программирования. Примером быстрого счетчика будет Scala, где (0 == false) возвращает false, и я уверен, что Scala не единственный язык программирования, который возвращает false при сравнении числа с логическим значением.
Роб Уилтон
2
Хорошо понял! Тогда, скажем, в большинстве языков программирования.
Паоло Ровелли
3
В JavaScript причина 0 == falseвозврата в trueтом, что оператор двойного равенства выполняет приведение типов. Однако с оператором тройного равенства 0 === falseвозвращается false, потому что «число» и «логическое значение» - это разные типы.
jkdev
1
@PaoloRovelli, в Lua, Ruby и Clojure, 0 обрабатывается как trueв условных выражениях . В Rust and Go 0и false есть разные типы, которые нельзя сравнивать на равенство.
скутер болтаться
0

Null - это особый тип объекта, такой как:

>>>type(None)
<class 'NoneType'>

Вы можете проверить, находится ли объект в классе 'NoneType':

>>>variable = None
>>>variable is None
True

Более подробная информация доступна на Python Docs


источник
-1

В соответствии со значением проверки Истины , None напрямую проверяется как FALSE, поэтому будет достаточно простейшего выражения:

if not foo:
artejera
источник
3
Нет не будет Это выражение будет возвращаться Trueдля любого ложного значения, а не только None.
insert_name_here
Правда, и простое «если не foo:» не ответит правильно на исходный вопрос, как указано. Тем не менее, Python динамически типизирован и предлагает сократить синтаксические протоколы, поэтому мне кажется правильным рассмотреть более простые, похожие конструкции.
artejera