obiekt null w Pythonie?
Jak odnosić się do obiektu null w Pythonie?
5 answers
W Pythonie obiekt 'null' to singleton None
.
Najlepszym sposobem sprawdzenia rzeczy pod kątem "Noneness" jest użycie operatora tożsamości, is
:
if foo is None:
...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-20 11:54:27
Nie nazywa się null jak w innych językach, Ale None
. Zawsze istnieje tylko jedna instancja tego obiektu, więc możesz sprawdzić równoważność z x is None
(porównanie tożsamości) zamiast x == None
, jeśli chcesz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-20 11:56:34
None
, Python ' s null?
Nie ma null
w Pythonie, zamiast tego jest None
. Jak już wspomniano, najdokładniejszym sposobem sprawdzenia, czy coś zostało podane None
jako wartość, jest użycie operatora tożsamości is
, który sprawdza, czy dwie zmienne odnoszą się do tego samego obiektu.
>>> foo is None
True
>>> foo = 'bar'
>>> foo is None
False
Podstawy
Istnieje i może być tylko jeden None
None
jest jedyną instancją klasy NoneType
i wszelkimi dalszymi próbami utworzenia instancji tej klasy zwróci ten sam obiekt, co czyni None
singletonem. Nowi użytkownicy Pythona często widzą komunikaty o błędach, które wspominają NoneType
i zastanawiają się, co to jest. To moja osobista opinia, że te wiadomości mogą po prostu wspomnieć None
po imieniu, ponieważ, jak zobaczymy wkrótce, {32]} pozostawia niewiele miejsca na dwuznaczność. Więc jeśli widzisz jakieś TypeError
wiadomość, która wspomina, że NoneType
nie można zrobić tego lub nie można zrobić tamtego, po prostu wiedz, że to po prostu ten None
został użyty w taki sposób, że nie mogę.
Ponadto, None
jest wbudowaną stałą, gdy tylko uruchomisz Pythona, jest ona dostępna do użycia z każdego miejsca, czy to w module, klasie, czy funkcji. NoneType
dla kontrastu nie jest, musisz najpierw uzyskać odniesienie do niego, pytając None
o jego klasę.
>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType
Możesz sprawdzić unikalność None
Za pomocą funkcji tożsamości Pythona id()
. Zwraca unikalny numer przypisany do obiektu, każdy obiekt ma taki. Jeśli identyfikator dwóch zmiennych jest taki sam, to wskazują na fakt do tego samego obiektu.
>>> 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
nie można nadpisać
W znacznie starszej wersji Pythona (przed 2.4) można było ponownie przypisać None
, ale już nie. Nawet jako atrybut klasy lub w ramach funkcji.
# 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
Można więc bezpiecznie założyć, że wszystkie odniesienia None
są takie same. Nie ma "zwyczaju" None
.
Aby przetestować na None
użyj operatora is
Pisząc kod możesz pokusić się o przetestowanie Noneness like this:
if value==None:
pass
Lub testować na fałsz w ten sposób
if not value:
pass
Musisz zrozumieć implikacje i dlaczego często dobrze jest być wyraźnym.
Przypadek 1: sprawdzanie, czy wartość jest None
Dlaczego to zrobić
value is None
Zamiast
value==None
Pierwsza jest równoważna:
id(value)==id(None)
Natomiast wyrażenie value==None
jest w rzeczywistości stosowane w ten sposób
value.__eq__(None)
Jeśli wartość rzeczywiście jest None
wtedy dostaniesz to, czego oczekiwałeś.
>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True
W większości przypadków wynik będzie taki sam, ale metoda __eq__()
otwiera drzwi, które unieważniają gwarancję dokładności, ponieważ może być nadpisana w klasie, aby zapewnić specjalne zachowanie.
Rozważ tę klasę.
>>> class Empty(object):
... def __eq__(self, other):
... return not other
Więc przymierzasz None
i działa
>>> empty = Empty()
>>> empty==None
True
Ale wtedy działa również na pustym łańcuchu
>>> empty==''
True
A jednak
>>> ''==None
False
>>> empty is None
False
Przypadek 2: Użycie None
jako boolean
Następujące dwa testy
if value:
# do something
if not value:
# do something
Są w rzeczywistości oceniane jako
if bool(value):
# do something
if not bool(value):
# do something
None
jest" false", co oznacza, że jeśli zostanie rzucona na boolean, zwróci False
, a jeśli zastosuje się operator not
, zwróci True
. Należy jednak pamiętać, że nie jest to właściwość unikalna dla None
. Oprócz samej False
, właściwość jest współdzielona przez puste listy, krotki, zestawy, dikty, łańcuchy, a także przez 0 i wszystkie obiekty z klas, które implementują metodę magiczną __bool__()
do return 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
W ten sposób, podczas testowania zmiennych w następujący sposób, należy być dodatkowo świadomym tego, co włączasz lub wyłączasz z testu: [106]}
def some_function(value=None):
if not value:
value = init_value()
W powyższym przykładzie, czy chodziło Ci o wywołanie init_value()
, gdy wartość jest ustawiona konkretnie na None
, czy chodziło Ci o to, że wartość ustawiona na 0
, pusty łańcuch lub pusta lista również powinny wywołać inicjalizację. Jak mówiłem, bądź uważny. Jak to często bywa w Pythonie explicit jest lepszy niż implicit .
None
w praktyce
None
używany jako wartość sygnału
None
ma specjalny status w Pythonie. Jest to ulubiona Wartość bazowa, ponieważ wiele algorytmów traktuje ją jako wyjątkową wartość. W takich scenariuszach może być używany jako znacznik, aby zasygnalizować, że warunek wymaga specjalnej obsługi (np. ustawienia wartości domyślnej).
Możesz przypisać None
do argumentów kluczowych funkcji, a następnie jawnie przetestować to.
def my_function(value, param=None):
if param is None:
# do something outrageous!
Możesz zwrócić go jako domyślny, gdy próbujesz dostać się do atrybutu obiektu, a następnie jawnie przetestować go przed wykonaniem czegoś specjalnego.
value = getattr(some_obj, 'some_attribute', None)
if value is None:
# do something spectacular!
Domyślnie metoda słownika get()
zwraca None
podczas próby uzyskania dostępu do nieistniejącego klucza:
>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True
Jeśli spróbujesz uzyskać do niego dostęp za pomocą notacji dolnej a KeyError
zostanie podniesione
>>> value = some_dict['foo']
KeyError: 'foo'
Podobnie jeśli spróbujesz pop nieistniejącego pozycja
>>> value = some_dict.pop('foo')
KeyError: 'foo'
Które można wyłączyć za pomocą domyślnej wartości, która jest zwykle ustawiona na None
value = some_dict.pop('foo', None)
if value is None:
# booom!
None
używane jako flaga i poprawna wartość
Opisane powyżej zastosowania None
mają zastosowanie, gdy nie jest uważana za prawidłową wartość, ale raczej jako sygnał do zrobienia czegoś specjalnego. Są jednak sytuacje, w których czasami ważne jest, aby wiedzieć, skąd None
pochodzi, ponieważ nawet jeśli jest używany jako sygnał, może być również częścią danych.
Kiedy zapytujesz obiekt o jego atrybut za pomocą getattr(some_obj, 'attribute_name', None)
odzyskanie None
nie powie Ci, czy atrybut, do którego próbowałeś uzyskać dostęp, był ustawiony na None
lub czy był całkowicie nieobecny w obiekcie. Ta sama sytuacja, gdy uzyskujesz dostęp do klucza ze słownika, takiego jak some_dict.get('some_key')
, nie wiesz, czy brakuje some_dict['some_key']
, czy jest on po prostu ustawiony na None
. Jeśli potrzebujesz tych informacji, standardowym sposobem obsługi tego problemu jest bezpośrednia próba uzyskania dostępu do atrybutu lub klucza z poziomu try/except
konstruktor:
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)
Podobnie z 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)
Powyższe dwa przykłady pokazują, jak obsługiwać przypadki obiektów i słownika, a co z funkcjami? To samo, ale w tym celu używamy argumentu słowa kluczowego 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
używane tylko jako ważna wartość
Jeśli okaże się, że Twój kod jest zaśmiecony powyższym wzorcem try/except
, aby odróżnić znaczniki None
od danych None
, po prostu użyj innej wartości testowej. Jest wzorzec, w którym wartość wykraczająca poza zestaw ważnych wartości jest wstawiana jako część danych w strukturze danych i jest używana do kontrolowania i testowania specjalnych warunków (np. granic, stanu, itp.). Taka wartość nazywa się sentinel i może być używana w sposób None
jako sygnał. Tworzenie Sentinela w Pythonie jest trywialne.
undefined = object()
Obiekt undefined
powyżej jest unikalny i nie robi zbyt wiele z niczego, co może być interesujące dla programu, jest więc doskonałym zastępuje None
jako flagę. Obowiązują pewne zastrzeżenia, więcej o tym po kodzie.
Z funkcją
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
Z 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
Z obiektem
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
Jak wspomniałem wcześniej custom sentinels mają pewne zastrzeżenia. Po pierwsze, nie są to słowa kluczowe jak None
, więc python ich nie chroni. Możesz nadpisać undefined
powyżej w dowolnym momencie, w dowolnym miejscu zdefiniowanego modułu, więc uważaj, jak je ujawniasz i używasz. Następnie instancja zwracane przez object()
nie jest singletonem, jeśli wykonasz to połączenie 10 razy, otrzymasz 10 różnych obiektów. W końcu użycie Sentinela jest wysoce idiosynkratyczne. Sentinel jest specyficzny dla biblioteki, w której jest używany i jako taki jego zakres powinien być ogólnie ograniczony do wewnętrznych bibliotek. Nie powinno się "wyciekać". Zewnętrzny kod powinien być o tym świadomy tylko wtedy, gdy jego celem jest rozszerzenie lub uzupełnienie API biblioteki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-31 03:32:36
W Pythonie, aby reprezentować brak wartości, możesz użyć typów None value (.NoneType.None ) dla obiektów i "" (lub len() == 0) na sznurki. Dlatego:
if yourObject is None: # if yourObject == None:
...
if yourString == "": # if yourString.len() == 0:
...
Jeśli chodzi o różnicę między " = = "I" is", testowanie tożsamości obiektu za pomocą "= = " powinno być wystarczające. Jednakże, ponieważ operacja " is "jest zdefiniowana jako operacja tożsamości obiektu, prawdopodobnie bardziej poprawne jest jej użycie niż"==". Nie wiem, czy istnieje nawet różnica prędkości.
W każdym razie możesz rzucić okiem na:
- Python wbudowane stałe strona doc.
- Python testowanie wartości prawdy strona doc.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-03 11:11:50
Per testowanie wartości prawdy , 'None' bezpośrednio testuje jako FALSE, więc najprostsze wyrażenie wystarczy:
if not foo:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-24 23:15:42