null об’єкт у Python?


Відповіді:


1627

У Python об'єктом 'null' є синглтон None.

Найкращий спосіб перевірити речі на "Noneness" - це використовувати оператор ідентифікації is:

if foo is None:
    ...

125
І причина вибору egg is Noneбільш egg == None: Останні можуть бути перевантажені, і, ймовірно, ламаються при порівнянні дійсного об'єкта None (залежить від того, як це реалізовано, але не очікує , що все взяти порівняння з None до уваги, що не так чи що?) , хоча isзавжди працює те саме.

94
Чому дизайнери пітона просто не вибрали "null". Просто має бути іншим, чи не так! ;)
Відар

35
@Vidar 'None' - це не відсутність об'єкта (як 'null', нульова посилання), це фактичний об'єкт. Ви ніколи не отримаєте об'єкт "None", що передається для об'єкта, який є типом нічого іншого, крім "NoneType". Це також не мовна концепція. Це не вбудована мова Python, це частина стандартної бібліотеки Python. Нічого! == (
ах

11
@ naught101 Це не послужило б меті; як немає поняття покажчиків. Якщо ви використовуєте бібліотеку ctypes, None не буде використовуватися як синонім нульової адреси, але все ще немає мовної концепції «null reference». У Python ви завжди залишаєте посилання на якийсь об’єкт, навіть якщо цей об'єкт є None. Я підозрюю, що це значно спрощує мову.
Rushyo

5
чудова презентація, що пояснює "помилку в мільярд доларів", яка є нульовою посиланням: infoq.com/presentations/… . Інші параметри замість нуля - це параметри, або Можливо (спеціальні).
Майкл Трув

133

None, Нуль Python?

У nullPython немає , натомість є 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є "фальсією", що означає, що якщо присвоєно булевому значенню, воно повернеться, 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

Якщо ви намагаєтеся отримати доступ до нього за допомогою позначення підписки, 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)

Наведені вище приклади показують, як обробляти об'єкти та словарі, що стосується функцій? Те саме, але для цього ми використовуємо аргумент ключового слова подвійних зірочок:

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

@hkBst Я здогадуюсь, що ваше питання стосується того, як python оцінює рівність. Подивіться на цю stackoverflow.com/questions/3588776 / ...
Майкл Ekoka

Ах, так IIUC, що зазвичай все-таки закінчується дзвінок .__ eq__? У такому випадку я відкликаю свою пропозицію.
hkBst

@MichaelEkoka можете поділитися джерелом для цієї вражаючої та корисної інформації.
Анідха Бхатнагар

Стандартна практика. Ви можете знайти деякі підказки про те, щоб пройти підручник з Python , але читати вихідний код популярних проектів - моя порада номер один, щоб швидко зануритися в ідіоматичний Python .
Майкл Екока

67

Це не називається null, як в інших мовах, але None. Завжди є лише один екземпляр цього об’єкта, тому ви можете перевірити на еквівалентність x is None(порівняння ідентичності) замість x == None, якщо хочете.


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:
    ...

Щодо різниці між "==" та "є", тестування на предмет об'єкта з використанням "==" повинно бути достатнім. Однак, оскільки операція "є" визначається як операція ідентичності об'єкта, ймовірно, правильніше використовувати її, а не "==". Не впевнений, чи є навіть різниця швидкостей.

У будь-якому випадку, ви можете подивитися:


8
Наскільки я знаю, (0 == false) повертає true у КОЖНІЙ мові програмування. Це тому, що помилкове кодується як 0, а «істинне» як все, що НЕ 0. Однак, будь ласка, не зазначайте, що оператор «є» не той самий, як «==». Це більш-менш однакова різниця між "==" і "дорівнює" в Java. Оператор "є", дійсно, перевіряє, чи ДВА ОБ'ЄКТИ однакові (той самий екземпляр і НЕ той самий вміст)!
Паоло Ровеллі

12
Paolo, FYI, (0 == false) не повертає true у кожній мові програмування. Швидким прикладом лічильника може бути Scala, де (0 == false) повертає false, і я впевнений, що Scala - не єдина мова програмування, яка повертає false під час порівняння числа з булевим.
Роб Вілтон

2
Добре, зрозумів! Тоді, скажімо, у більшості мов програмування.
Паоло Ровеллі

3
У JavaScript причина 0 == falseповертається trueчерез те, що оператор з подвійним рівнем вводить примус. Однак оператор з потрійними рівняннями 0 === falseповертається false, оскільки "число" та "булеве" різні типи.
jkdev

1
@PaoloRovelli, у Луа, Рубі та Клуджуре 0 трактується як trueу умовних умовах. У Іржа і Go, 0і false різні типи , які не можуть бути порівняні для рівності.
скутер-бовтанок

0

Null - це особливий тип об'єкта, як:

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

Ви можете перевірити, чи є об’єкт у класі "NoneType":

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

Більше інформації можна отримати в Python Docs


-1

За тестування значення Істини «None» прямо не перевіряє , як FALSE, так що простий вислів буде досить:

if not foo:

3
Ні, не буде. Цей вислів поверне Trueдля будь-якого falsy значення, а не тільки None.
insert_name_here

Правда, і простий "як не foo:" не відповів би правильно на початкове запитання, як було зазначено. Однак python динамічно набирається і пропонує запрошувати зменшити синтаксичні протоколи, тому мені здається дійсним розглянути більш прості, подібні конструкції.
artejera
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.