Mengapa tuple berisi item yang bisa berubah?

178

Jika sebuah tuple tidak berubah maka mengapa bisa berisi item yang bisa berubah?

Tampaknya merupakan kontradiksi bahwa ketika item yang bisa berubah seperti daftar memang dimodifikasi, tupel miliknya tetap dipertahankan.

qazwsx
sumber

Jawaban:

205

Itu pertanyaan yang sangat bagus.

Wawasan kunci adalah bahwa tupel tidak memiliki cara untuk mengetahui apakah objek di dalamnya bisa berubah. Satu-satunya hal yang membuat objek bisa berubah adalah memiliki metode yang mengubah datanya. Secara umum, tidak ada cara untuk mendeteksi ini.

Wawasan lain adalah bahwa wadah Python sebenarnya tidak mengandung apa pun. Sebagai gantinya, mereka menyimpan referensi ke objek lain. Demikian juga, variabel Python tidak seperti variabel dalam bahasa yang dikompilasi; sebaliknya nama variabel hanyalah kunci dalam kamus namespace di mana mereka dikaitkan dengan objek yang sesuai. Ned Batchhelder menjelaskan ini dengan baik di posting blognya . Either way, objek hanya tahu jumlah referensi mereka; mereka tidak tahu apa referensi itu (variabel, wadah, atau internal Python).

Bersama-sama, kedua wawasan ini menjelaskan misteri Anda (mengapa tuple abadi "berisi" daftar tampaknya berubah ketika daftar yang mendasarinya berubah). Faktanya, tuple tidak berubah (masih memiliki referensi yang sama ke objek lain seperti sebelumnya). Tuple tidak dapat berubah (karena tidak memiliki metode bermutasi). Ketika daftar berubah, tuple tidak mendapat pemberitahuan tentang perubahan (daftar tidak tahu apakah itu dirujuk oleh variabel, tuple, atau daftar lain).

Sementara kita berada di topik, berikut adalah beberapa pemikiran lain untuk membantu melengkapi model mental Anda tentang apa tuple, bagaimana mereka bekerja, dan penggunaan yang dimaksudkan:

  1. Tuples dikarakterisasi lebih sedikit oleh kekekalannya dan lebih karena tujuan yang dimaksudkan.
    Tuples adalah cara Python untuk mengumpulkan informasi yang heterogen di bawah satu atap. Misalnya, s = ('www.python.org', 80) menyatukan string dan angka sehingga pasangan host / port dapat diedarkan sebagai soket, objek komposit. Dilihat dalam cahaya itu, sangat masuk akal untuk memiliki komponen yang bisa berubah.

  2. Kekekalan berjalan seiring dengan sifat lain, hashabilitas . Tetapi hashability bukan properti mutlak. Jika salah satu komponen tuple tidak hashable, maka tuple keseluruhan juga tidak hashable. Misalnya, t = ('red', [10, 20, 30])bukan hashable.

Contoh terakhir menunjukkan 2-tupel yang berisi string dan daftar. Tuple itu sendiri tidak bisa berubah-ubah (artinya tidak memiliki metode apa pun untuk mengubah kontennya). Demikian juga, string tidak dapat diubah karena string tidak memiliki metode mutasi. Objek daftar memang memiliki metode mutasi, sehingga dapat diubah. Ini menunjukkan bahwa mutabilitas adalah properti dari jenis objek - beberapa objek memiliki metode bermutasi dan beberapa tidak. Ini tidak berubah hanya karena objek bersarang.

Ingat dua hal. Pertama, kekekalan bukanlah sihir - itu hanyalah ketiadaan metode bermutasi. Kedua, objek tidak tahu variabel atau wadah apa yang merujuk mereka - mereka hanya tahu jumlah referensi.

Semoga ini bermanfaat bagi Anda :-)

Raymond Hettinger
sumber
Tidak salah "tupel tidak memiliki cara untuk mengetahui apakah objek di dalamnya bisa berubah." Kita dapat mendeteksi jika referensi mengimplementasikan metode hash, maka itu tidak berubah. Seperti dic atau set akan dilakukan. Bukankah ini lebih merupakan keputusan desain untuk tuple apa yang dimaksudkan?
garg10mungkin
@ garg10may 1) Hashibilitas tidak mudah dideteksi tanpa memanggil hash()karena semua yang diwarisi dari objek () adalah hashable dan subclass perlu secara eksplisit mematikan hashing. 2) Hashibilitas tidak menjamin keabadian - mudah untuk membuat contoh objek hashable yang bisa berubah. 3) Tuple, seperti kebanyakan wadah di Python, hanya memiliki referensi ke objek yang mendasarinya - mereka tidak berkewajiban untuk memeriksanya dan membuat kesimpulan tentangnya.
Raymond Hettinger
171

Itu karena tupel tidak mengandung daftar, string, atau angka. Mereka berisi referensi ke objek lain . 1 Ketidakmampuan untuk mengubah urutan referensi yang terdapat pada sebuah tuple tidak berarti bahwa Anda tidak dapat mengubah objek yang terkait dengan referensi tersebut. 2

1. Objek, nilai, dan tipe (lihat: kedua hingga paragraf terakhir)
2. Hirarki jenis standar (lihat: "Urutan tidak dapat diubah")

Ignacio Vazquez-Abrams
sumber
8
Ada ambiguitas dalam pertanyaan itu. Jawaban ini sepenuhnya menjelaskan mengapa mungkin untuk tupel mengandung benda bisa berubah. Itu tidak menjelaskan mengapa tuple dirancang untuk berisi objek yang bisa berubah. Saya pikir yang terakhir adalah pertanyaan yang lebih relevan.
pengirim
16

Pertama-tama, kata "abadi" dapat berarti banyak hal berbeda bagi orang yang berbeda. Saya terutama menyukai bagaimana Eric Lippert mengkategorikan ketidakmampuan dalam posting blognya . Di sana, ia mendaftar jenis-jenis kekekalan ini:

  • Kekekalan Realio-trulio
  • Ketidakberubahan sekali tulis
  • Ketidakstabilan popsicle
  • Ketidaksuburan dalam vs dangkal
  • Fasad abadi
  • Ketidakberesan pengamatan

Ini dapat digabungkan dalam berbagai cara untuk membuat lebih banyak jenis ketidakberdayaan, dan saya yakin lebih ada. Jenis kekekalan Anda tampaknya tertarik pada kekekalan mendalam (juga dikenal sebagai transitif), di mana objek tidak kekal hanya dapat berisi objek kekal lainnya.

Poin utama dari hal ini adalah bahwa ketidakberdayaan yang dalam hanya satu dari banyak, banyak jenis ketidakberdayaan. Anda dapat mengadopsi jenis apa pun yang Anda sukai, selama Anda sadar bahwa gagasan Anda tentang "abadi" mungkin berbeda dari gagasan orang lain tentang "abadi".

Ken Wayne VanderLinde
sumber
Apa jenis ketidakmampuan yang dimiliki Python tuple?
qazwsx
3
Tuple Python memiliki kekekalan dangkal (alias non-transitif).
Ken Wayne VanderLinde
16

Seperti yang saya pahami, pertanyaan ini perlu diulangi sebagai pertanyaan tentang keputusan desain: Mengapa desainer Python memilih untuk membuat tipe urutan yang tidak berubah yang dapat berisi objek yang bisa berubah?

Untuk menjawab pertanyaan ini, kita harus berpikir tentang tujuan tupel melayani: mereka berfungsi sebagai cepat , tujuan umum urutan. Dengan mengingat hal itu, menjadi cukup jelas mengapa tupel tidak dapat diubah tetapi dapat berisi objek yang bisa berubah. Yakni:

  1. Tuples cepat dan hemat memori: Tuples lebih cepat dibuat daripada daftar karena tidak dapat diubah. Kekekalan berarti tupel dapat dibuat sebagai konstanta dan dimuat demikian, menggunakan pelipatan konstan . Ini juga berarti mereka lebih cepat dan lebih efisien memori untuk dibuat karena tidak perlu untuk keseluruhan lokasi, dll. Mereka sedikit lebih lambat dari daftar untuk akses item acak, tetapi lebih cepat lagi untuk membongkar (setidaknya pada mesin saya). Jika tuple bisa berubah, maka mereka tidak akan secepat untuk tujuan seperti ini.

  2. Tuples adalah tujuan umum : Tuples harus dapat berisi segala jenis objek. Mereka terbiasa (dengan cepat) melakukan hal-hal seperti daftar argumen panjang variabel (melalui *operator dalam definisi fungsi). Jika tuple tidak bisa menahan benda yang bisa berubah, mereka tidak akan berguna untuk hal-hal seperti ini. Python harus menggunakan daftar, yang mungkin akan memperlambat segalanya, dan tentu saja akan kurang efisien memori.

Jadi Anda lihat, untuk memenuhi tujuannya, tupel harus tidak berubah, tetapi juga harus dapat berisi objek yang bisa berubah. Jika perancang Python ingin membuat objek abadi yang menjamin bahwa semua objek yang dikandungnya "juga tidak berubah, mereka harus membuat tipe urutan ketiga. Keuntungan tidak sebanding dengan kompleksitas ekstra.

pengirim
sumber
12

Anda tidak dapat mengubah iditem-itemnya. Jadi akan selalu berisi item yang sama.

$ python
>>> t = (1, [2, 3])
>>> id(t[1])
12371368
>>> t[1].append(4)
>>> id(t[1])
12371368
kev
sumber
Ini adalah demonstrasi yang paling tepat dari contoh di atas. Tuple memiliki referensi ke objek-objek yang tidak berubah, meskipun memiliki paling banyak satu komponen yang dapat berubah membuat seluruh tuple tidak dapat dilawan.
piepi
5

Saya akan pergi mengambil risiko di sini dan mengatakan bahwa bagian yang relevan di sini adalah bahwa sementara Anda dapat mengubah isi daftar, atau keadaan suatu objek, yang terkandung dalam sebuah tuple, apa yang tidak dapat Anda ubah adalah bahwa objek tersebut atau daftarnya ada di sana. Jika Anda memiliki sesuatu yang bergantung pada sesuatu [3] menjadi daftar, bahkan jika kosong, maka saya dapat melihat ini berguna.


sumber
3

Salah satu alasannya adalah bahwa tidak ada cara umum dalam Python untuk mengubah tipe yang bisa berubah menjadi yang tidak dapat diubah (lihat PEP 351 yang ditolak , dan diskusi terkait mengapa itu ditolak). Dengan demikian, tidak mungkin untuk meletakkan berbagai jenis objek dalam tupel jika memiliki batasan ini, termasuk hampir semua objek non-hashable yang dibuat pengguna.

Satu-satunya alasan bahwa kamus dan set memiliki batasan ini adalah bahwa mereka memerlukan objek yang dapat hashable, karena mereka diimplementasikan secara internal sebagai tabel hash. Tetapi perhatikan bahwa, ironisnya, kamus dan set itu sendiri tidak dapat diubah (atau hashable). Tuples tidak menggunakan hash objek, jadi kemampuan berubah-ubahnya tidak masalah.

penilai
sumber
2

Sebuah tuple tidak berubah dalam arti bahwa tuple itu sendiri tidak dapat mengembang atau mengecil, tidak semua barang yang terkandung sendiri tidak dapat diubah. Kalau tidak, tupel itu membosankan.

adamsmith
sumber