Memahami operator "adalah" Python


110

The isoperator tidak sesuai dengan nilai-nilai variabel, tetapi kasus itu sendiri.

Apa sebenarnya maksudnya itu?

Saya mendeklarasikan dua variabel bernama xdan ymenetapkan nilai yang sama di kedua variabel, tetapi mengembalikan false ketika saya menggunakan isoperator.

Saya butuh klarifikasi. Ini kode saya.

x = [1, 2, 3]
y = [1, 2, 3]

print(x is y)  # It prints false!

Jawaban:


181

Anda salah paham tentang apa yang isdiuji operator. Ini menguji jika dua variabel menunjuk objek yang sama , bukan jika dua variabel memiliki nilai yang sama.

Dari dokumentasi untuk isoperator :

Operator isdan is notpengujian untuk identitas objek: x is ybenar jika dan hanya jika xdan yadalah objek yang sama.

Gunakan ==operator sebagai gantinya:

print(x == y)

Ini cetakan True. xdan ydua daftar terpisah :

x[0] = 4
print(y)  # prints [1, 2, 3]
print(x == y)   # prints False

Jika Anda menggunakan id()fungsi tersebut, Anda akan melihatnya xdan ymemiliki pengenal yang berbeda:

>>> id(x)
4401064560
>>> id(y)
4401098192

tetapi jika Anda akan menetapkan yke xmaka keduanya menunjuk ke objek yang sama:

>>> x = y
>>> id(x)
4401064560
>>> id(y)
4401064560
>>> x is y
True

dan ismenunjukkan keduanya adalah objek yang sama, ia mengembalikan True.

Ingatlah bahwa dalam Python, nama hanyalah label yang mereferensikan nilai ; Anda dapat memiliki beberapa nama yang mengarah ke objek yang sama. ismemberi tahu Anda jika dua nama menunjuk ke satu dan objek yang sama. ==memberi tahu Anda jika dua nama merujuk ke objek yang memiliki nilai yang sama.


13
Jadi, A is Bsama saja dengan id(A) == id(B).
imallett

2
@imallett: itu proxy untuk pengujian yang sama, asalkan Anda tidak menyimpan id(A)dalam variabel dan nanti berharap variable == id(B)untuk tetap bekerja; jika Adihapus sementara itu maka Bbisa saja diberi lokasi memori yang sama.
Martijn Pieters

1
Tidak dapat memformat dalam komentar. Namun ada hal yang menarik. :) >>> x = 5 \n>>> y = 5 \n>>> x adalah y \nBenar \n>>> x == y \nBenar \n>>>\n
Haranadh

5
Integer kecil dimasukkan ke dalam CPython karena sering digunakan. Ini adalah pengoptimalan. x = 5; y = 5; x adalah y => Benar karena id (x) == id (y). Ini adalah objek bilangan bulat yang sama yang digunakan kembali. Bekerja dengan Python karena integer tidak dapat diubah. Jika Anda melakukan x = 1,0; y = 1.0 atau x = 9999; y = 9999, itu tidak akan menjadi identitas yang sama, karena float dan int yang lebih besar tidak disimpan.
Magnus Lyckå

1
@ MagnusLyckå ada pengoptimalan lain yang dapat menyebabkan objek tetap disimpan di cache. Misalnya, jika Anda menjalankan contoh di fungsi baru atau bersama-sama dengan titik koma pemisah di interpreter interaktif, Anda akan menemukan bahwa mereka juga memiliki id yang sama.
Martijn Pieters

60

Duplikat lain menanyakan mengapa dua string yang sama umumnya tidak identik, yang sebenarnya tidak dijawab di sini:

>>> x = 'a' 
>>> x += 'bc'
>>> y = 'abc'
>>> x == y
True
>>> x is y
False

Jadi, mengapa mereka tidak memiliki string yang sama? Terutama mengingat ini:

>>> z = 'abc'
>>> w = 'abc'
>>> z is w
True

Mari kita tunda bagian kedua sebentar. Bagaimana yang pertama bisa benar?

Penerjemah harus memiliki "tabel interning", tabel yang memetakan nilai string ke objek string, jadi setiap kali Anda mencoba membuat string baru dengan konten 'abc', Anda mendapatkan objek yang sama. Wikipedia memiliki diskusi yang lebih rinci tentang cara kerja magang.

Dan Python memiliki tabel interning string; Anda bisa memasukkan string internal secara manual dengan sys.internmetode ini.

Faktanya, Python diizinkan untuk secara otomatis menyimpan tipe yang tidak dapat diubah, tetapi tidak diharuskan untuk melakukannya. Implementasi yang berbeda akan memiliki nilai yang berbeda pula.

CPython (implementasi yang Anda gunakan jika Anda tidak tahu implementasi mana yang Anda gunakan) auto-interns bilangan bulat kecil dan beberapa singlet khusus seperti False, tetapi bukan string (atau bilangan bulat besar, atau tupel kecil, atau apa pun). Anda dapat melihat ini dengan mudah:

>>> a = 0
>>> a += 1
>>> b = 1
>>> a is b
True
>>> a = False
>>> a = not a
>>> b = True
a is b
True
>>> a = 1000
>>> a += 1
>>> b = 1001
>>> a is b
False

Oke, tapi kenapa zdan widentik?

Itu bukan interpreter yang secara otomatis melakukan intern, itulah nilai lipat kompilator.

Jika waktu kompilasi yang sama string yang muncul dua kali dalam modul yang sama (apa sebenarnya berarti ini sulit untuk menentukan-itu bukan hal yang sama sebagai literal string yang, karena r'abc', 'abc'dan 'a' 'b' 'c'semua literal berbeda tetapi sama string tetapi mudah dimengerti secara intuitif), kompilator hanya akan membuat satu turunan dari string, dengan dua referensi.

Faktanya, kompilator dapat melangkah lebih jauh: 'ab' + 'c'dapat dikonversi 'abc'oleh pengoptimal, dalam hal ini dapat dilipat bersama dengan 'abc'konstanta dalam modul yang sama.

Sekali lagi, ini adalah sesuatu yang diperbolehkan Python tetapi tidak wajib dilakukan. Tetapi dalam kasus ini, CPython selalu melipat string kecil (dan juga, misalnya, tupel kecil). (Meskipun compiler pernyataan-demi-pernyataan interpreter interaktif tidak menjalankan pengoptimalan yang sama seperti compiler module-at-a-time, jadi Anda tidak akan melihat hasil yang persis sama secara interaktif.)


Jadi, apa yang harus Anda lakukan sebagai programmer?

Yah… tidak ada. Anda hampir tidak pernah memiliki alasan untuk peduli jika dua nilai yang tidak dapat diubah itu identik. Jika Anda ingin tahu kapan Anda bisa menggunakan a is balih-alih a == b, Anda menanyakan pertanyaan yang salah. Selalu gunakan a == bkecuali dalam dua kasus:

  • Untuk perbandingan yang lebih mudah dibaca dengan nilai tunggal seperti x is None.
  • Untuk nilai yang bisa berubah, saat Anda perlu mengetahui apakah mutasi xakan memengaruhi y.

1
Penjelasan yang sangat bagus, terutama saran Anda di akhir.
DavidG

Terima kasih atas penjelasan detailnya. Apakah ada yang tahu: jika wdan zidentik karena nilai lipat kompiler, mengapa ini juga bekerja di REPL, bahkan menggunakan id()untuk memeriksa referensi? Menggunakan REPL pada Python 3.7
Chi-chi

8

ishanya mengembalikan nilai true jika mereka sebenarnya adalah objek yang sama. Jika mereka sama, perubahan yang satu juga akan muncul di yang lain. Inilah contoh perbedaannya.

>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> print x is y
False
>>> z = y
>>> print y is z
True
>>> print x is z
False
>>> y[0] = 5
>>> print z
[5, 2, 3]

8

Dipicu oleh pertanyaan duplikat , analogi ini mungkin berhasil:

# - Darling, I want some pudding!
# - There is some in the fridge.

pudding_to_eat = fridge_pudding
pudding_to_eat is fridge_pudding
# => True

# - Honey, what's with all the dirty dishes?
# - I wanted to eat pudding so I made some. Sorry about the mess, Darling.
# - But there was already some in the fridge.

pudding_to_eat = make_pudding(ingredients)
pudding_to_eat is fridge_pudding
# => False

3
Bisa jadi hanya selera pribadi (tidak ada permainan kata-kata) tetapi saya menemukan analogi ini lebih membingungkan daripada membantu dan membuat saya ingin makan puding ketika saya tidak memilikinya di lemari es saya :( Saya pikir jawaban Mark Ransom, meskipun lebih membosankan, adalah mungkin lebih instruktif
Tom Close

1
@TomClose: Ada banyak jawaban bagus untuk pertanyaan ini, cukup sehingga ada ruang untuk kesembronoan. Juga, saya ingin puding juga.
Amadan

5

isdan is notmerupakan dua operator identitas di Python. isoperator tidak membandingkan nilai variabel, tetapi membandingkan identitas variabel. Pertimbangkan ini:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> hex(id(a))
'0x1079b1440'
>>> hex(id(b))
'0x107960878'
>>> a is b
False
>>> a == b
True
>>>

Contoh di atas menunjukkan kepada Anda bahwa identitas (bisa juga menjadi alamat memori di Cpython) berbeda untuk keduanya adan b(meskipun nilainya sama). Itulah mengapa ketika Anda mengatakan a is bitu mengembalikan salah karena ketidakcocokan dalam identitas kedua operan. Namun ketika Anda mengatakan a == b, itu mengembalikan true karena ==operasi hanya memverifikasi jika kedua operan memiliki nilai yang sama yang ditetapkan padanya.

Contoh menarik (untuk kelas ekstra):

>>> del a
>>> del b
>>> a = 132
>>> b = 132
>>> hex(id(a))
'0x7faa2b609738'
>>> hex(id(b))
'0x7faa2b609738'
>>> a is b
True
>>> a == b
True
>>>

Dalam contoh di atas, meskipun adan bmerupakan dua variabel berbeda, a is bdikembalikan True. Ini karena tipe ais intyang merupakan objek tetap. Jadi python (saya kira untuk menghemat memori) mengalokasikan objek yang sama bketika dibuat dengan nilai yang sama. Jadi dalam kasus ini, identitas variabel cocok dan a is bternyata True.

Ini akan berlaku untuk semua objek yang tidak dapat diubah:

>>> del a
>>> del b
>>> a = "asd"
>>> b = "asd"
>>> hex(id(a))
'0x1079b05a8'
>>> hex(id(b))
'0x1079b05a8'
>>> a is b
True
>>> a == b
True
>>>

Semoga membantu.


ini adalah contoh yang sangat bagus. terima kasih untuk info detailnya.
Haranadh

Tapi coba a = 123456789 b = 123456789
user2183078

Segala sesuatu yang kurang dari -5atau lebih tinggi dari 256di Python akan menjadi False. Python menyimpan angka dalam rentang [-5, 256].
pintar

Tidak semua objek yang tidak dapat diubah akan dibagikan saat Anda tunjukkan, itu adalah pengoptimalan yang diterapkan oleh runtime Python untuk beberapa objek tetapi tidak untuk yang lain. Proses berbagi bilangan bulat kecil didokumentasikan dengan baik, tetapi menurut saya ini bukan untuk interning string .
Mark Ransom

4

x is ysama dengan id(x) == id(y), membandingkan identitas objek.

Seperti yang ditunjukkan @ tomasz-kurgan pada komentar di bawah, isoperator berperilaku tidak biasa dengan objek tertentu.

Misalnya

>>> class A(object):
...   def foo(self):
...     pass
... 
>>> a = A()
>>> a.foo is a.foo
False
>>> id(a.foo) == id(a.foo)
True

Ref;
https://docs.python.org/2/reference/expressions.html#is-not
https://docs.python.org/2/reference/expressions.html#id24


Tidak, tidak. Ini mungkin berperilaku serupa dalam banyak kasus, tetapi itu tidak selalu benar. Lihat ini - bagian paling bawah halaman, poin 6 .:> (...), Anda mungkin memperhatikan perilaku yang tampaknya tidak biasa dalam penggunaan operator is tertentu , seperti yang melibatkan perbandingan antara metode instance, atau konstanta Dan contoh kerja minimal : `class A (object): def foo (self): pass a = A () print a.foo adalah a.foo print id (a.foo) == id (a.foo)`
Tomasz Kurgan

3

Seperti yang Anda lihat di sini ke bilangan bulat kecil. Angka di atas 257 bukanlah int kecil, jadi dihitung sebagai objek yang berbeda.

Lebih baik digunakan ==sebagai gantinya dalam kasus ini.

Informasi lebih lanjut ada di sini: http://docs.python.org/2/c-api/int.html


2

X menunjuk ke sebuah larik, Y menunjuk ke larik yang berbeda. Array tersebut identik, tetapi isoperator akan melihat pointer tersebut, yang tidak identik.


5
Python tidak memiliki pointer. Anda perlu memperketat terminologi Anda.
David Heffernan

3
Itu dilakukan secara internal, seperti Java dan banyak bahasa lainnya. Faktanya, isfungsionalitas operator menunjukkan ini.
Neko

5
Detail implementasi bukanlah yang terpenting. Dokumentasi menggunakan terminologi "identitas objek". Anda juga harus. "Operator sedang dan tidak menguji identitas objek: x adalah y benar jika dan hanya jika x dan y adalah objek yang sama. X bukan y menghasilkan nilai kebenaran terbalik."
David Heffernan

1
@ Neko: CPython secara internal menggunakan pointer. Tapi jelas Jython (diimplementasikan di Java) dan PyPy (diimplementasikan dalam subset Python) tidak menggunakan pointer. Di PyPy, beberapa objek bahkan tidak akan memiliki idkecuali Anda memintanya.
abarnert

1

Ini membandingkan identitas objek, yaitu, apakah variabel merujuk ke objek yang sama dalam memori. Ini seperti ==di Java atau C (saat membandingkan pointer).


1

Contoh sederhana dengan buah-buahan

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist is newfruitlist )
print ( fruitlist is verynewfruitlist )
print ( newfruitlist is verynewfruitlist )

Keluaran:

True
False
False

Jika kamu mencoba

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist == newfruitlist )
print ( fruitlist == verynewfruitlist )
print ( newfruitlist == verynewfruitlist )

Outputnya berbeda:

True
True
True

Itu karena operator == hanya membandingkan konten variabel. Untuk membandingkan identitas 2 variabel, gunakan operator is

Untuk mencetak nomor identifikasi:

print ( id( variable ) )

-3

The isOperator hanyalah versi bahasa Inggris dari ==. Karena ID dari kedua list berbeda maka jawabannya salah. Anda dapat mencoba:

a=[1,2,3]
b=a
print(b is a )#True

* Karena ID dari kedua daftar akan sama


isbukan 'versi bahasa Inggris =='
David Buck
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.