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

Как я могу ссылаться на нулевой объект в Python?

5 ответов


в Python объект "null" является одноэлементным None.

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

if foo is None:
    ...

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


None, Python null?

нет 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(). Возвращает уникальный номер, присвоенный объект, у каждого объекта есть один. Если идентификатор двух переменных одинаков, то они фактически указывают на один и тот же объект.

>>> 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 оператор

при написании кода у вас может возникнуть желание проверить Noneness такой:

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 является "falsey", что означает, что если в булевой он вернется False и если использовать not оператор он вернет True. Обратите внимание, однако, что это не свойство, уникальное для None. В дополнение к свойство является общим для пустых списков, кортежей, множеств, предсказывает, струны, а также 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

если вы попытаетесь получить к нему доступ, используя нотацию индекса a 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)

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

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 используется в качестве сигнала. Тривиально создавать sentinel в 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

с dict

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


в Python, чтобы представить отсутствие значения, вы можете использовать нет значение (типы.NoneType.Нет!--3-->) для объектов и "" (или len () = = 0) для строк. Таким образом:

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

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

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

в любом случае, вы можете посмотреть на:


Per правда стоимость тестирования,' None ' напрямую проверяет как FALSE, поэтому достаточно самого простого выражения:

if not foo: