Jak odwoływać się do obiektu zerowego w Pythonie?
Jak odwoływać się do obiektu zerowego w Pythonie?
Odpowiedzi:
W Pythonie „zerowym” obiektem jest singleton None.
Najlepszym sposobem sprawdzenia rzeczy pod kątem „Noneness” jest użycie operatora tożsamości is:
if foo is None:
...
NonePython jest zerowy?W nullPythonie nie ma None. Jak już wspomniano, najdokładniejszym sposobem sprawdzenia, czy coś zostało podane Nonejako wartość, jest użycie isoperatora tożsamości, który sprawdza, czy dwie zmienne odnoszą się do tego samego obiektu.
>>> foo is None
True
>>> foo = 'bar'
>>> foo is None
False
NoneNonejest jedyną instancją klasy NoneTypei wszelkie dalsze próby utworzenia tej klasy zwrócą ten sam obiekt, co spowoduje Noneutworzenie singletonu. Nowi użytkownicy Pythona często widzą komunikaty o błędach, które wspominają NoneTypei zastanawiają się, co to jest. Moim osobistym zdaniem te wiadomości mogą po prostu wspomnieć Nonepo imieniu, ponieważ, jak zobaczymy wkrótce, Nonepozostawia niewiele miejsca na dwuznaczność. Więc jeśli zobaczysz jakieś TypeErrorprzesłanie, które wspomina, że NoneTypenie może tego zrobić lub nie może tego zrobić, po prostu wiedz, że to po prostu taki, Nonektóry był używany w sposób, którego nie może.
Ponadto Nonejest wbudowaną stałą, gdy tylko uruchamiasz Python, można go używać z dowolnego miejsca, czy to w module, klasie czy funkcji. NoneTypew przeciwieństwie do tego nie trzeba, najpierw trzeba by się do niego odwołać, sprawdzając Nonejego klasę.
>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType
Możesz sprawdzić Noneunikalność za pomocą funkcji tożsamości Pythona id(). Zwraca unikalny numer przypisany do obiektu, każdy obiekt ma jeden. Jeśli identyfikator dwóch zmiennych jest taki sam, to w rzeczywistości wskazują na ten sam obiekt.
>>> 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 zastąpićW dużo starszej wersji Pythona (wcześniejszej niż 2.4) możliwe było ponowne przypisanie 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
Dlatego można bezpiecznie założyć, że wszystkie Noneodniesienia są takie same. Nie ma „niestandardowego” None.
Noneużycie isoperatoraPodczas pisania kodu możesz ulec pokusie przetestowania Noneness w następujący sposób:
if value==None:
pass
Lub przetestować pod kątem fałszu w ten sposób
if not value:
pass
Musisz zrozumieć konsekwencje i dlaczego często dobrym pomysłem jest mówienie wprost.
Noneczemu to robić
value is None
zamiast
value==None
Pierwszy jest równoważny z:
id(value)==id(None)
Podczas gdy wyrażenie value==Nonejest w rzeczywistości stosowane w ten sposób
value.__eq__(None)
jeśli wartość jest naprawdę None, otrzymasz to, czego się spodziewałeś.
>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True
W najczęstszych przypadkach wynik będzie taki sam, ale __eq__()metoda otwiera drzwi, które unieważniają jakąkolwiek gwarancję dokładności, ponieważ można ją zastąpić w klasie, aby zapewnić specjalne zachowanie.
Rozważ tę klasę.
>>> class Empty(object):
... def __eq__(self, other):
... return not other
Więc wypróbuj Nonei działa
>>> empty = Empty()
>>> empty==None
True
Ale potem działa również na pusty ciąg
>>> empty==''
True
I jeszcze
>>> ''==None
False
>>> empty is None
False
Nonejako wartości logicznejNastępne 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
Nonejest „falsey”, co oznacza, że jeśli zostanie ustawiony na wartość logiczną, zwróci Falsei jeśli zastosuje notoperator, zwróci True. Pamiętaj jednak, że nie jest to właściwość unikalna dla None. Oprócz Falsesiebie właściwość jest wspólna dla pustych list, krotek, zestawów, dykt, ciągów, a także 0 i wszystkich obiektów z klas, które implementują __bool__()magiczną metodę powrotu 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
Dlatego podczas testowania zmiennych w następujący sposób zwracaj szczególną uwagę na to, co włączasz lub wyłączasz z testu:
def some_function(value=None):
if not value:
value = init_value()
W powyższym przypadku, czy chciałeś zadzwonić, init_value()gdy wartość jest ustawiona konkretnie na None, czy miałeś na myśli, że wartość ustawiona na 0, pusty ciąg znaków lub pusta lista powinna również inicjować inicjalizację. Tak jak powiedziałem, bądź ostrożny. Jak to często bywa w Pythonie, jawne jest lepsze niż niejawne .
None w praktyceNone używany jako wartość sygnałuNonema specjalny status w Pythonie. Jest to ulubiona wartość wyjściowa, ponieważ wiele algorytmów traktuje ją jako wartość wyjątkową. W takich scenariuszach można go użyć jako flagi, aby zasygnalizować, że warunek wymaga specjalnej obsługi (np. Ustawienia wartości domyślnej).
Możesz przypisać Noneargumentom słowa kluczowego funkcji, a następnie jawnie ją przetestować.
def my_function(value, param=None):
if param is None:
# do something outrageous!
Możesz przywrócić go jako domyślny, gdy próbujesz dostać się do atrybutu obiektu, a następnie jawnie go przetestować przed zrobieniem czegoś specjalnego.
value = getattr(some_obj, 'some_attribute', None)
if value is None:
# do something spectacular!
Domyślnie get()metoda słownika powraca Nonepodczas 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 indeksu dolnego KeyError, zostanie podniesiony
>>> value = some_dict['foo']
KeyError: 'foo'
Podobnie jeśli spróbujesz rozbić nieistniejący element
>>> value = some_dict.pop('foo')
KeyError: 'foo'
które można ukryć za pomocą domyślnej wartości, która zwykle jest ustawiona na None
value = some_dict.pop('foo', None)
if value is None:
# booom!
None używany zarówno jako flaga, jak i poprawna wartośćOpisane powyżej zastosowania Nonemają zastosowanie, gdy nie jest uważane za prawidłową wartość, ale bardziej przypomina sygnał do zrobienia czegoś specjalnego. Są jednak sytuacje, w których czasem ważne jest, aby wiedzieć, skąd Nonepochodzi, ponieważ nawet jeśli jest używany jako sygnał, może również stanowić część danych.
Kiedy pytasz obiekt o jego atrybut z getattr(some_obj, 'attribute_name', None)powrotem None, nie mówi ci, czy atrybut, do którego próbujesz uzyskać dostęp, został ustawiony, Noneczy też był całkowicie nieobecny w obiekcie. Ta sama sytuacja podczas uzyskiwania dostępu do klucza ze słownika, np. some_dict.get('some_key')Nie wiesz, czy go some_dict['some_key']brakuje, czy po prostu jest ustawiony na None. Jeśli potrzebujesz tych informacji, zwykłym sposobem radzenia sobie z nimi jest bezpośrednia próba uzyskania dostępu do atrybutu lub klucza z poziomu try/exceptkonstrukcji:
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łowników, a co z funkcjami? To samo, ale w tym celu używamy argumentu słowa kluczowego podwójnej gwiazdki:
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 poprawna wartośćJeśli stwierdzisz, że Twój kod jest zaśmiecony powyższym try/exceptwzorcem, aby odróżnić Noneflagi i Nonedane, użyj innej wartości testowej. Istnieje wzorzec, w którym wartość, która nie mieści się w zestawie prawidłowych wartości, jest wstawiana jako część danych w strukturze danych i służy do kontrolowania i testowania warunków specjalnych (np. Granic, stanu itp.). Taką wartość nazywa się wartownikiem i można ją wykorzystać tak, Nonejak sygnał. Utworzenie wartownika w Pythonie jest banalne.
undefined = object()
Powyższy undefinedobiekt jest wyjątkowy i nie robi nic, co mogłoby zainteresować program, dlatego jest doskonałym zamiennikiem Nonejako flaga. 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 dyktando
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 przedmiotem
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, niestandardowi strażnicy mają pewne zastrzeżenia. Po pierwsze, nie są one słowami kluczowymi None, więc Python ich nie chroni. Możesz zastąpić undefinedpowyższe w dowolnym momencie, w dowolnym miejscu w module, który jest zdefiniowany, więc bądź ostrożny, jak je ujawnić i używać. Następnie instancja zwrócona przez object()nie jest singletonem, jeśli wykonasz to wywołanie 10 razy, otrzymasz 10 różnych obiektów. Wreszcie użycie wartownika jest bardzo idiosynkratyczne. Wartownik jest specyficzny dla biblioteki, w której jest używany i jako taki, jego zakres powinien zasadniczo być ograniczony do wewnętrznych elementów biblioteki. Nie powinien „wyciec”. Kod zewnętrzny powinien wiedzieć o tym tylko, jeśli ich celem jest rozszerzenie lub uzupełnienie interfejsu API biblioteki.
Nazywa się nie zerowy jak w innych językach, ale None. Zawsze jest 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.
None. Wtedy wszyscy mądrzy ludzie, którzy porównali się z nimi NoneType, zatriumfują!
W Pythonie, aby reprezentować brak wartości, możesz użyć wartości None ( types.NoneType.None ) dla obiektów i „” (lub len () == 0 ) dla łańcuchów. W związku z tym:
if yourObject is None: # if yourObject == None:
...
if yourString == "": # if yourString.len() == 0:
...
Jeśli chodzi o różnicę między „==” a „is”, wystarczające powinno być sprawdzenie tożsamości obiektu za pomocą „==”. Ponieważ jednak operacja „jest” jest zdefiniowana jako operacja tożsamości obiektu, prawdopodobnie bardziej poprawne jest użycie jej niż „==”. Nie jestem pewien, czy występuje nawet różnica prędkości.
W każdym razie możesz spojrzeć na:
0 == falsezwraca truesię tak, ponieważ dwukrotnie równa operator wykonuje typu przymus. Jednak z operatorem triple-equals 0 === falsezwraca wartość false, ponieważ „liczba” i „wartość logiczna” są różnymi typami.
truewarunkowo. W Rust and Go, 0i false są różne typy, które nie mogą być porównywane dla równości.
Null to specjalny typ obiektu, taki jak:
>>>type(None)
<class 'NoneType'>
Możesz sprawdzić, czy obiekt należy do klasy „NoneType”:
>>>variable = None
>>>variable is None
True
Więcej informacji jest dostępnych w Python Docs
W przypadku testowania wartości według prawdy „Brak” testuje bezpośrednio jako FAŁSZ, więc wystarczy najprostsze wyrażenie:
if not foo:
Truedo dowolnej wartości falsy nie tylko None.
egg is Noneprzezegg == None: Te ostatnie mogą być przeciążone, a może złamać przy porównywaniu ważny obiekt z None (w zależności od tego, jak to jest realizowane, ale nie należy się spodziewać, wszyscy wziąć Porównania z Żaden pod uwagę, prawda?) , podczas gdyiszawsze działa tak samo.