Apakah ada perbedaan antara “foo is None” dan “foo == None”?

217

Apakah ada perbedaan antara:

if foo is None: pass

dan

if foo == None: pass

Konvensi yang saya lihat di sebagian besar kode Python (dan kode yang saya tulis sendiri) adalah yang pertama, tetapi saya baru-baru menemukan kode yang menggunakan yang terakhir. Tidak ada yang merupakan instance (dan satu-satunya instance, IIRC) dari NoneType, jadi itu tidak masalah, kan? Apakah ada keadaan yang memungkinkan?

Joe Shaw
sumber

Jawaban:

253

isselalu kembali Truejika membandingkan instance objek yang sama

Padahal ==pada akhirnya ditentukan oleh __eq__()metode

yaitu


>>> class Foo(object):
       def __eq__(self, other):
           return True

>>> f = Foo()
>>> f == None
True
>>> f is None
False
Brendan
sumber
51
Anda mungkin ingin menambahkan bahwa Tidak ada yang tunggal sehingga "Tidak Ada adalah Tidak Ada" selalu Benar.
e-satis
43
Dan Anda mungkin ingin menambahkan bahwa isoperator tidak dapat dikustomisasi (kelebihan beban oleh kelas yang ditentukan pengguna).
martineau
@study Metode __eq__(self)ini adalah metode bawaan khusus yang menentukan bagaimana ==ditangani ketika digunakan pada objek Python. Di sini kita telah menimpanya sehingga ketika ==digunakan pada objek bertipe Fooitu selalu mengembalikan true. Tidak ada metode yang setara untuk isoperator sehingga perilaku istidak dapat diubah dengan cara yang sama.
Brendan
Apakah karena definisi kelas foo tidak memiliki konstruktor, yaitu fungsi init ?
belajar
49

Anda mungkin ingin membaca identitas objek dan kesetaraan ini .

Pernyataan 'is' digunakan untuk identitas objek, memeriksa apakah objek merujuk ke instance yang sama (alamat yang sama dalam memori).

Dan pernyataan '==' mengacu pada persamaan (nilai yang sama).

borrego
sumber
Hmmm, saya pikir tautan Anda berubah, kecuali jika Anda tertarik pada cara memanggil fungsi eksternal dari python
Pat
Saya baru saja mencoba a=1;b=1;print(a is b) # True. Adakah yang tahu mengapa itu a is bternyata benar bahkan jika mereka tampak sebagai 2 objek yang berbeda (alamat berbeda dalam memori)?
Johnny Chiu
24

Sebuah kata peringatan:

if foo:
  # do something

Apakah tidak persis sama dengan:

if x is not None:
  # do something

Yang pertama adalah tes nilai boolean dan dapat mengevaluasi false dalam konteks yang berbeda. Ada sejumlah hal yang mewakili false dalam tes nilai boolean misalnya wadah kosong, nilai boolean. Tidak ada yang juga menilai false dalam situasi ini tetapi hal-hal lain juga berlaku.

Tendayi Mawushe
sumber
12

(ob1 is ob2) sama dengan (id(ob1) == id(ob2))

Mykola Kharechko
sumber
6
... tapi (ob adalah ob2) jauh lebih cepat. Timeit mengatakan "(a is b)" adalah 0,0365 usec per loop dan "(id (a) == id (b))" adalah 0,153 usec per loop. 4.2x lebih cepat!
AKX
4
yang isversi membutuhkan tidak ada panggilan fungsi, dan tidak ada python-interpreter atribut lookup sama sekali; penerjemah dapat langsung menjawab jika ob1 sebenarnya adalah ob2.
u0b34a0f6ae
17
Tidak. {} is {}itu salah dan id({}) == id({})bisa (dan ada di CPython) benar. Lihat stackoverflow.com/questions/3877230
Piotr Dobrogost
12

Alasannya foo is Noneadalah cara yang disukai adalah bahwa Anda mungkin menangani objek yang mendefinisikan sendiri __eq__, dan yang mendefinisikan objek sama dengan Tidak ada. Jadi, selalu gunakan foo is Nonejika Anda perlu melihat apakah itu benar None.

truppo
sumber
8

Tidak ada perbedaan karena benda yang identik tentu akan sama. Namun, PEP 8 dengan jelas menyatakan bahwa Anda harus menggunakan is:

Perbandingan dengan lajang seperti Tidak ada harus selalu dilakukan dengan atau tidak, tidak pernah operator kesetaraan.

Thijs van Dien
sumber
7

istes untuk identitas, bukan kesetaraan. Untuk pernyataan Anda foo is none, Python hanya membandingkan alamat memori objek. Itu berarti Anda mengajukan pertanyaan, "Apakah saya memiliki dua nama untuk objek yang sama?"

==di sisi lain menguji kesetaraan yang ditentukan oleh __eq__()metode. Itu tidak peduli tentang identitas.

In [102]: x, y, z = 2, 2, 2.0

In [103]: id(x), id(y), id(z)
Out[103]: (38641984, 38641984, 48420880)

In [104]: x is y
Out[104]: True

In [105]: x == y
Out[105]: True

In [106]: x is z
Out[106]: False

In [107]: x == z
Out[107]: True

Noneadalah operator tunggal. Jadi None is Noneselalu benar.

In [101]: None is None
Out[101]: True
ChillarAnand
sumber
5

Untuk Tidak Ada seharusnya tidak ada perbedaan antara kesetaraan (==) dan identitas. The NoneType mungkin mengembalikan identitas untuk kesetaraan. Karena None adalah satu-satunya contoh yang dapat Anda buat dari NoneType (saya pikir ini benar), kedua operasi itu sama. Dalam kasus jenis lain ini tidak selalu terjadi. Sebagai contoh:

list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"

Ini akan mencetak "Sama" karena daftar memiliki operasi perbandingan yang bukan pengembalian identitas secara default.

Stephen Pellicer
sumber
5

@ Jason :

Saya sarankan menggunakan sesuatu yang lebih sesuai

if foo:
    #foo isn't None
else:
    #foo is None

Saya tidak suka menggunakan "jika foo:" kecuali foo benar-benar mewakili nilai boolean (yaitu 0 atau 1). Jika foo adalah string atau objek atau sesuatu yang lain, "if foo:" mungkin berfungsi, tetapi sepertinya jalan pintas malas bagi saya. Jika Anda memeriksa untuk melihat apakah x adalah Tidak ada, katakan "jika x adalah Tidak ada:".

Graeme Perrow
sumber
Memeriksa string / daftar kosong dengan "jika var" adalah cara yang disukai. Konversi Boolean didefinisikan dengan baik, dan ini adalah kode yang kurang yang bahkan berkinerja lebih baik. Tidak ada alasan untuk melakukan "if len (mylist) == 0" misalnya.
truppo
Salah. Misalkan foo = "". Kemudian if fooakan kembali salah dan komentar #foo is Nonesalah.
blokeley
Catatan untuk downvoters - jawaban saya mengutip jawaban yang telah dihapus dan tidak setuju dengannya. Jika Anda tidak suka kode dalam jawaban saya, Anda perlu memperbarui . :-)
Graeme Perrow
2

Beberapa detail lebih lanjut:

  1. The isklausul sebenarnya memeriksa apakah dua objects berada pada lokasi memori yang sama atau tidak. yaitu apakah mereka berdua menunjuk ke lokasi memori yang sama dan memiliki yang sama id.

  2. Sebagai konsekuensi dari 1, ismemastikan apakah, atau tidak, dua yang diwakili secara leksikal objectmemiliki atribut yang identik (atribut-atribut ...) atau tidak

  3. Instansiasi dari tipe primitif seperti bool, int, string(dengan beberapa pengecualian), NoneTypememiliki nilai yang sama akan selalu berada di lokasi memori yang sama.

Misalnya

>>> int(1) is int(1)
True
>>> str("abcd") is str("abcd")
True
>>> bool(1) is bool(2)
True
>>> bool(0) is bool(0)
True
>>> bool(0)
False
>>> bool(1)
True

Dan karena NoneTypehanya dapat memiliki satu contoh dari dirinya sendiri dalam tabel "look-up" python karena itu yang pertama dan yang terakhir lebih dari gaya pemrograman pengembang yang menulis kode (mungkin untuk konsistensi) daripada memiliki alasan logis yang halus untuk pilih satu dari yang lain.

Jari-jari yang berdarah
sumber
2
Semua orang membaca ini: JANGAN gunakan some_string is "bar"untuk membandingkan string PERNAH. Tidak ada alasan tunggal yang dapat diterima untuk melakukannya dan itu akan pecah ketika Anda tidak mengharapkannya. Fakta bahwa itu sering berhasil adalah hanya karena CPython tahu itu akan bodoh untuk membuat dua objek abadi yang memiliki konten yang sama. Tapi itu bisa terjadi.
ThiefMaster
@ThiefMaster apakah jawabannya cenderung disalahartikan? Padahal, setelah membacanya lagi saya tidak bisa menemukannya (dengan menyebutkan "beberapa pengecualian"). Pernyataan Anda hanya berlaku untuk string dan tidak int, kan?
Bleeding Fingers
Tidak juga, tetapi karena Anda memiliki contoh itu dalam jawaban Anda, saya pikir itu akan menjadi ide yang baik untuk memperingatkan pengguna bahwa itu adalah ide yang buruk untuk benar-benar menggunakannya. Mungkin tambahkan sesuatu seperti "# cpython spesifik / tidak dijamin" di belakang kalimat itu ...
ThiefMaster
1

Kesimpulan John Machin yang Nonemerupakan singleton adalah kesimpulan yang didukung oleh kode ini.

>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>> 

Karena Nonesingleton, x == Nonedan x is Noneakan memiliki hasil yang sama. Namun, menurut pendapat estetika saya, x == Noneitu yang terbaik.

ncmathsadist
sumber
2
Saya tidak setuju dengan pendapat di akhir jawaban ini. Ketika membandingkan dengan tidak ada secara eksplisit, biasanya dimaksudkan bahwa objek yang dimaksud adalah objek yang tepat None. Sebagai perbandingan, seseorang jarang melihat Tidak ada yang digunakan dalam konteks lain apa pun kecuali untuk menjadi serupa Falsedengan nilai-nilai lain yang benar. Dalam kasus-kasus seperti itu, lebih idiomatis untuk melakukan sesuatu sepertiif x: pass
SingleNegationElimination
0
a is b # returns true if they a and b are true alias
a == b # returns true if they are true alias or they have values that are deemed equivalence 


a = [1,3,4]
b = a[:] #creating copy of list
a is b # if gives false
False
a == b # gives true
True
Aks
sumber