Python'da null nesne?


Yanıtlar:


1629

Python'da 'null' nesnesi singleton'dur None.

Bir şeyi "Noneness" için kontrol etmenin en iyi yolu kimlik operatörünü kullanmaktır is:

if foo is None:
    ...

125
Ve seçilmesinin sebebi egg is Noneüzerinde egg == None: ikincisi (öyle mi, nasıl uygulandığı bağlıdır, ancak herkesin dikkate None ile karşılaştırmalar almaya sanmıyoruz?) Aşırı ve Hiçbiri ile geçerli nesneyi karşılaştırırken bozulma olasılığı bulunuyor olabilir , isher zaman aynı şekilde çalışır.

94
neden python tasarımcıları sadece "boş" seçmediler. Sadece farklı olmalısın, değil mi? ;)
Vidar

35
@Vidar 'Hiçbiri' bir nesnenin eksikliği değildir ('null', null bir referans olduğu için), gerçek bir nesnedir. 'NoneType' dışında bir tür nesne için asla 'None' nesnesini geçiremezsiniz. Aynı zamanda bir dil konsepti de değildir .. Python'da yerleşik değildir, Python'un standart kütüphanesinin bir parçasıdır. Yok! == (ahem) Null
Rushyo

11
@ naught101 Hiçbir amaca hizmet etmezdi; çünkü işaretçi kavramı yoktur. Ctypes kütüphanesini kullanıyorsanız Hiçbiri, adres sıfırıyla eşanlamlı olarak kullanılacaktır, ancak yine de 'boş başvuru' için dil kavramı yoktur. Python'da, bu nesne Yok olsa bile, her zaman bir tür nesneye başvurmayı bıraktınız. Bunun dili büyük ölçüde basitleştirdiğinden şüpheleniyorum.
Rushyo

5
'milyar dolarlık hatayı' açıklayan harika sunum null ref: infoq.com/presentations/… . Null yerine diğer seçenekler Seçenekler veya Belki (özel) türleridir.
Michael Trouw

134

None, Python boş mu?

nullPython'da yok , bunun yerine var None. Daha önce de belirtildiği gibi, bir şeyin Nonedeğer olarak verildiğini test etmenin en doğru yolu is, iki değişkenin aynı nesneye atıfta bulunduğunu test eden kimlik operatörünü kullanmaktır .

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

Temeller

Sadece bir tane var ve olabilir None

Nonesınıfın tek örneğidir ve bu sınıfı NoneTypesomutlaştırmak için yapılan herhangi bir girişim aynı nesneyi döndürür ve bu da Nonetekil bir ton oluşturur. Python'a yeni gelenler genellikle NoneTypebunun ne olduğunu belirten ve merak eden hata mesajlarını görürler . Benim kişisel görüşüm, bu mesajların sadece Noneisminden bahsedebileceği için, kısa bir süre sonra göreceğimiz gibi, Nonebelirsizliğe çok az yer bırakıyor. Dolayısıyla , bunu yapamayan veya yapamayan bir TypeErrormesaj görürseniz NoneType, sadece Nonebunun yapamayacağı şekilde kullanılan mesaj olduğunu bilin .

Ayrıca, Noneyerleşik bir sabittir, Python'u başlatır başlatmaz modül, sınıf veya işlevde her yerden kullanılabilir. NoneTypeaksine, Nonesınıfını sorgulayarak ilk önce bir referans almanız gerekir .

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

None'In benzersizliğini Python'un kimlik fonksiyonu ile kontrol edebilirsiniz id(). Bir nesneye atanan benzersiz sayıyı döndürür, her nesnenin bir tane vardır. İki değişkenin kimliği aynı ise, aslında aynı nesneye işaret ederler.

>>> 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 üzerine yazılamaz

Python'un çok daha eski bir versiyonunda (2.4'ten önce) yeniden atamak mümkün None, ancak artık değil. Sınıf özniteliği olarak veya bir işlevin sınırlarında bile.

# 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

Bu nedenle, tüm Nonereferansların aynı olduğunu varsaymak güvenlidir . "Özel" yok None.

Operatörü Nonekullanmayı test etmek içinis

Kod yazarken Noneness'i böyle test etmek isteyebilirsiniz :

if value==None:
    pass

Ya da böyle bir yanlışlığı test etmek için

if not value:
    pass

Sonuçları ve neden açık olmanın genellikle iyi bir fikir olduğunu anlamalısınız.

Durum 1: Bir değerin None

neden bunu yapıyorsun

value is None

ziyade

value==None

Birincisi şuna eşittir:

id(value)==id(None)

İfade value==Noneaslında böyle uygulanırken

value.__eq__(None)

değer gerçekten ise Noneo zaman ne beklediğiniz alırsınız.

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

Çoğu durumda sonuç aynı olacaktır, ancak __eq__()yöntem herhangi bir doğruluk garantisini geçersiz kılan bir kapı açar, çünkü özel davranış sağlamak için bir sınıfta geçersiz kılınabilir.

Bu sınıfı düşünün.

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

Yani deniyorsun Noneve işe yarıyor

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

Ama sonra boş dizede de çalışır

>>> empty==''
True

Ve henüz

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

Durum 2: NoneBoole olarak kullanma

Aşağıdaki iki test

if value:
    # do something

if not value:
    # do something

aslında şu şekilde değerlendiriliyor

if bool(value):
    # do something

if not bool(value):
    # do something

None"falsey" dir, yani bir boole gönderilirse geri döner Falseve notoperatör uygulandığında geri döner True. Ancak bunun benzersiz bir özellik olmadığını unutmayın None. FalseKendisine ek olarak , özellik boş listeler, tuples, kümeler, dikteler, dizeler yanı sıra 0 ve __bool__()geri dönmek için sihirli yöntemi uygulayan sınıflardan tüm nesneler tarafından paylaşılır 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

Bu nedenle, değişkenleri aşağıdaki şekilde test ederken, teste neleri dahil ettiğiniz veya testin dışında bıraktığınız konusunda daha fazla bilgi sahibi olun:

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

Yukarıda, init_value()değer özellikle olarak ayarlandığında çağırmak Nonemı istediniz 0, yoksa boş bir dize olarak ayarlanmış bir değer mi yoksa boş bir liste mi yoksa boş bir listenin de başlatmayı tetiklemesi gerektiğini mi kastettiniz ? Dediğim gibi, dikkatli ol. Python'da açıkça olduğu gibi genellikle örtük olmaktan iyidir .

None uygulamada

None sinyal değeri olarak kullanılır

NonePython'da özel bir statüye sahiptir. Bu, favori bir temel değerdir, çünkü birçok algoritma bunu olağanüstü bir değer olarak görür. Bu tür senaryolarda, bir koşulun bazı özel işlem gerektirdiğini (varsayılan değerin ayarlanması gibi) işaret etmek için bir bayrak olarak kullanılabilir.

NoneBir işlevin anahtar kelime bağımsız değişkenlerine atayabilir ve sonra bunu açıkça test edebilirsiniz.

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

Bir nesnenin özniteliğine ulaşmaya çalışırken varsayılan olarak döndürebilir ve daha sonra özel bir şey yapmadan önce açıkça test edebilirsiniz.

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

Var olmayan bir anahtara erişmeye çalışırken varsayılan olarak bir sözlüğün get()yöntemi döndürülür None:

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

Abonelik notasyonunu kullanarak erişmeye KeyErrorçalışsaydınız a

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

Benzer şekilde, var olmayan bir öğeyi açmaya çalışırsanız

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

Genellikle varsayılan olarak ayarlanmış varsayılan bir değerle bastırabileceğiniz None

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

None hem bayrak hem de geçerli değer olarak kullanılır

Yukarıda açıklanan kullanımları, Nonegeçerli bir değer olarak kabul edilmediğinde, daha çok özel bir şey yapmak için bir sinyal gibi olduğunda geçerlidir. Ancak bazen nereden Nonegeldiğini bilmenin önemli olduğu durumlar vardır, çünkü bir sinyal olarak kullanılmasına rağmen verilerin bir parçası da olabilir.

Bir nesneyi getattr(some_obj, 'attribute_name', None)geri alma ile Noneözniteliği sorguladığınızda, erişmeye çalıştığınız özniteliğin ayarlanmış olup Noneolmadığını veya nesnede tamamen bulunmadığını bildirmez . Gibi bir sözlükten bir anahtara erişirken aynı durum , eksik olup olmadığını veya sadece olarak ayarlanmış olup some_dict.get('some_key')olmadığını bilmiyorsunuz . Bu bilgiye ihtiyacınız varsa, bunu ele almanın genel yolu, bir yapı içinden öznitelik veya anahtara doğrudan erişmeye çalışmaktır :some_dict['some_key']Nonetry/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)

Benzer şekilde:

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)

Yukarıdaki iki örnek, nesne ve sözlük vakalarının nasıl ele alınacağını gösterir, ya fonksiyonlar? Aynı şey, ancak bu amaçla double asterisks anahtar kelime argümanını kullanıyoruz:

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 yalnızca geçerli bir değer olarak kullanılır

Eğer try/exceptsadece Nonebayraklar ve Noneveriler arasında ayrım yapmak için kodunuzun yukarıdaki desenle dolu olduğunu fark ederseniz , sadece başka bir test değeri kullanın. Bir veri yapısındaki verilerin bir parçası olarak geçerli değerler kümesinin dışında kalan bir değerin eklendiği ve özel koşulları (ör. Sınırlar, durum vb.) Kontrol etmek ve test etmek için kullanıldığı bir model vardır. Böyle bir değere bir sentinel denir ve Nonebir sinyal olarak kullanılan şekilde kullanılabilir. Python'da bir nöbetçi oluşturmak önemsizdir.

undefined = object()

Yukarıdaki undefinednesne benzersizdir ve bir programın ilgisini çekebilecek hiçbir şey yapmaz, bu nedenle Nonebayrak olarak mükemmel bir alternatiftir . Bazı uyarılar geçerlidir, daha sonra koddan sonra.

Fonksiyonu ile

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

Dikte ile

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

Bir nesne ile

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

Daha önce de belirttiğim gibi, özel nöbetçiler bazı uyarılarla birlikte gelir. İlk olarak, bunlar gibi anahtar kelimeler değildir None, bu nedenle python onları korumaz. undefinedYukarıda tanımladığınız modülde herhangi bir yerde yukarıdakilerin üzerine yazabilirsiniz , bu yüzden bunları nasıl açığa çıkardığınıza ve kullandığınıza dikkat edin. Daha sonra, döndürülen örnek object()tekil değildir, bu çağrıyı 10 kez yaparsanız 10 farklı nesne elde edersiniz. Son olarak, bir nöbetçi kullanımı oldukça kendine özgüdür. Bir sentinel, kullanıldığı kütüphaneye özgüdür ve bu nedenle kapsamı genellikle kütüphanenin içi ile sınırlı olmalıdır. Dışarı sızmamalı. Harici kod, yalnızca amacı kütüphanenin API'sini genişletmek veya desteklemekse farkında olmalıdır.


Ne hakkında: Yok == şey?
hkBst

Sanırım sorunuz python'un eşitliği nasıl değerlendirdiğiyle ilgili. Bu stackoverflow.com/questions/3588776/…
Michael Ekoka

Ah, öyleyse IIUC, genellikle hala bir şey çağırıyor. Bu durumda öneriyi geri çekiyorum.
hkBst

@MichaelEkoka bu etkileyici ve faydalı bilgilerin kaynağını paylaşabilirsiniz.
Anidhya Bhatnagar

Standart pratik. Python öğreticisinden geçmenin bazı ipuçlarını bulabilirsiniz , ancak popüler projelerin kaynak kodunu okumak, kendinizi hızlı bir şekilde deyimsel Python'a sokmak için bir numaralı tavsiyem .
Michael Ekoka

67

Diğer dillerde olduğu gibi null olarak adlandırılmaz, ancak None. Bu nesnenin her zaman yalnızca bir örneği vardır, bu nedenle isterseniz x is Noneyerine (kimlik karşılaştırması) ile eşdeğer olup olmadığını kontrol edebilirsiniz x == None.


25
Yeniden başlatarak Python'u kırmanın bir yolunu bulacağım None. O zaman karşılaştırma yapan tüm zeki insanlar NoneTypezafer kazanacak!
Zenexer

28

Python'da, bir değerin yokluğunu temsil etmek için nesneler için Yok değerini ( types.NoneType.None ) ve dizeler için "" (veya len () == 0 ) kullanabilirsiniz. Bu nedenle:

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

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

"==" ve "is" arasındaki farkla ilgili olarak, "==" kullanarak nesne kimliği testi yeterli olmalıdır. Ancak, "is" işlemi nesne kimliği işlemi olarak tanımlandığından, "==" yerine onu kullanmak daha doğru olur. Hız farkı bile olup olmadığından emin değilim.

Her neyse, şunlara göz atabilirsiniz:


8
Bildiğim kadarıyla, (0 == false) HER programlama dilinde true değerini döndürür. Bunun nedeni, false değerinin 0 ve "true" olarak değil, NOT 0 olmayan her şey olarak kodlanmasıdır. Bu, Java'daki "==" ve "eşittir" arasındaki aşağı yukarı aynı farktır. "İs" operatörü aslında İKİ NESNEN'in aynı olup olmadığını kontrol eder (aynı örnek ve aynı içerik DEĞİL)!
Paolo Rovelli

12
Paolo, FYI, (0 == false) her programlama dilinde true değerini döndürmez. Hızlı sayaç örneği Scala, burada (0 == false) false döndürür ve bir sayıyla bir boole karşılaştırılırken false döndüren tek programlama dili Scala olmadığından eminim.
Rob Wilton

2
Tamam anladım! O zaman diyelim ki çoğu programlama dilinde.
Paolo Rovelli

3
JavaScript'inizde nedeni 0 == falsedöner trueoperatör tipi zorlama yapar çift eşittir çünkü. Bununla birlikte, üçlü eşit işleçle, 'sayı' ve 'boole' farklı türler olduğu için 0 === falsegeri döner false.
jkdev

1
@PaoloRovelli, Lua, Ruby ve Clojure'da, 0 truekoşullu olarak değerlendirilir. Rust ve Go'da 0ve false eşitlikle karşılaştırılamayan farklı türlerdir.
scooter-dangle

0

Null, aşağıdaki gibi özel bir nesne türüdür:

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

Bir nesnenin 'NoneType' sınıfında olup olmadığını kontrol edebilirsiniz:

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

Daha fazla bilgi Python Docs adresinde mevcuttur.


-1

Başına Gerçek değer testi basit ifadesi yeterli olacaktır böylece, 'Yok' doğrudan false olarak test eder:

if not foo:

3
Hayır, olmayacak. Bu ifade, sadece herhangi bir falsy değeri Trueiçin geri dönecektir . None
insert_name_here

Doğru ve basit "foo değilse:" belirtildiği gibi orijinal soruya doğru cevap vermez. Ancak, python dinamik olarak yazılmıştır ve sözdizimi protokollerini azaltmaya davet eder, bu yüzden benim için geçerli gibi görünüyor, daha basit, benzer yapıları düşünmeye.
artejera
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.