Saya bingung tentang tipe yang tidak bisa diubah. Saya tahu float
objek tersebut dianggap tidak dapat diubah, dengan jenis contoh ini dari buku saya:
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
Apakah ini dianggap tidak dapat diubah karena struktur kelas / hierarki ?, makna float
ada di bagian atas kelas dan merupakan pemanggilan metodenya sendiri. Mirip dengan jenis contoh ini (meskipun buku saya mengatakan dict
bisa berubah):
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Sedangkan sesuatu yang bisa berubah memiliki metode di dalam kelas, dengan jenis contoh ini:
class SortedKeyDict_a(dict):
def example(self):
return self.keys()
Juga, untuk yang terakhir class(SortedKeyDict_a)
, jika saya meneruskan jenis set ini ke sana:
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
tanpa memanggil example
metode, itu mengembalikan kamus. The SortedKeyDict
dengan __new__
bendera itu sebagai kesalahan. Saya mencoba meneruskan bilangan bulat ke RoundFloat
kelas __new__
dan ditandai tidak ada kesalahan.
sumber
Jawaban:
Apa? Mengapung tidak berubah? Tapi aku tidak bisa
Bukankah itu "mut" x?
Yah Anda setuju string tidak bisa diubah kan? Tetapi Anda dapat melakukan hal yang sama.
Nilai variabel berubah, tetapi berubah dengan mengubah apa yang dimaksud variabel. Jenis yang bisa berubah bisa berubah seperti itu, dan itu juga bisa berubah "di tempat".
Inilah perbedaannya.
Contoh nyata
sumber
def f(my_list): my_list = [1, 2, 3]
. Dengan pass-by-reference di C, nilai argumen bisa berubah dengan memanggil fungsi itu. Dengan Python, fungsi itu tidak melakukan apa-apa.def f(my_list): my_list[:] = [1, 2, 3]
akan melakukan sesuatu.a += b
kadang - kadang adalah mutasi. Dan fakta bahwa penugasan ke bagian dari objek yang lebih besar kadang-kadang berarti mutasi objek yang lebih besar, hanya tidak pernah mutasi bagian — misalnya,a[0] = b
tidak bermutasia[0]
, tetapi mungkin memang bermutasia
... Itulah sebabnya mungkin lebih baik untuk tidak mencoba meletakkan segala sesuatu dalam bentuk C ++ dan alih-alih hanya menggambarkan apa yang Python lakukan dengan caranya sendiri ...)Anda harus memahami bahwa Python mewakili semua datanya sebagai objek. Beberapa objek seperti daftar dan kamus dapat berubah, artinya Anda dapat mengubah kontennya tanpa mengubah identitasnya. Objek lain seperti integer, float, string dan tuple adalah objek yang tidak dapat diubah. Cara mudah untuk memahami itu adalah jika Anda telah melihat ID objek.
Di bawah ini Anda melihat string yang tidak dapat diubah. Anda tidak dapat mengubah kontennya. Ini akan memunculkan
TypeError
jika Anda mencoba mengubahnya. Juga, jika kami menetapkan konten baru, objek baru dibuat alih-alih konten yang dimodifikasi.Anda dapat melakukannya dengan daftar dan itu tidak akan mengubah identitas objek
Untuk membaca lebih lanjut tentang model data Python, Anda bisa melihat referensi bahasa Python:
sumber
Jenis abadi yang umum:
int()
,float()
,complex()
str()
,tuple()
,frozenset()
,bytes()
Jenis yang bisa berubah-ubah (hampir semuanya):
list()
,bytearray()
set()
dict()
Salah satu trik untuk dengan cepat menguji apakah suatu tipe bisa berubah atau tidak, adalah dengan menggunakan
id()
fungsi bawaan.Contohnya, menggunakan pada integer,
menggunakan daftar,
sumber
id()
. +1.id()
menyesatkan di sini. Objek yang diberikan akan selalu memiliki id yang sama selama masa hidupnya, tetapi objek yang berbeda yang ada pada waktu yang berbeda mungkin memiliki id yang sama karena pengumpulan sampah.Pertama-tama, apakah suatu kelas memiliki metode atau apa struktur kelasnya tidak ada hubungannya dengan mutabilitas.
int
s danfloat
s tidak berubah . Jika aku melakukanItu menunjuk nama
a
di suatu1
tempat di memori di baris pertama. Pada baris kedua, terlihat up yang1
, menambahkan5
, mendapat6
, maka poina
pada saat itu6
dalam memori - itu tidak mengubah yang1
ke6
cara apapun. Logika yang sama berlaku untuk contoh-contoh berikut, menggunakan tipe tidak berubah lainnya :Untuk tipe yang bisa berubah , saya dapat melakukan hal yang secara aktual mengubah nilai penyimpanannya . Dengan:
Saya telah membuat daftar lokasi
1
,2
dan3
di memori. Jika saya melakukannyaSaya hanya menunjuk
e
ke poin yang samalist
d
di. Saya kemudian dapat melakukan:Dan daftar yang menunjuk
e
dand
akan diperbarui juga memiliki lokasi4
dan5
dalam memori.Jika saya kembali ke tipe yang tidak dapat diubah dan melakukannya dengan
tuple
:Maka
f
masih hanya menunjuk ke aslinyatuple
- Anda telah menunjukg
pada yang sama sekali barutuple
.Sekarang, dengan contoh Anda
Di mana Anda lulus
(yang merupakan
tuple
darituples
) sebagaival
, Anda mendapatkan kesalahan karenatuple
s tidak memiliki.clear()
metode - Anda harus lulusdict(d)
sebagaival
untuk itu untuk bekerja, dalam hal ini Anda akan mendapatkan kosongSortedKeyDict
sebagai hasilnya.sumber
Jika Anda datang ke Python dari bahasa lain (kecuali bahasa yang sangat mirip Python, seperti Ruby), dan bersikeras memahaminya dalam hal bahasa lain, di sinilah orang biasanya bingung:
Dalam Python, tugas bukanlah mutasi dalam Python.
Di C ++, jika Anda menulis
a = 2
, Anda menelepona.operator=(2)
, yang akan mengubah objek yang disimpana
. (Dan jika ada itu tidak ada objek yang disimpan dalama
, itu kesalahan.)Dalam Python,
a = 2
tidak melakukan apa pun untuk apa pun yang disimpan dia
; itu hanya berarti bahwa2
sekarang disimpana
sebagai gantinya. (Dan jika ada yang tidak ada objek yang disimpan dalama
, itu bagus.)Pada akhirnya, ini adalah bagian dari perbedaan yang bahkan lebih dalam.
Variabel dalam bahasa seperti C ++ adalah lokasi yang diketik dalam memori. Jika
a
adalahint
, itu berarti 4 byte di suatu tempat yang diketahui oleh kompiler seharusnya ditafsirkan sebagaiint
. Jadi, ketika Anda melakukannyaa = 2
, itu mengubah apa yang disimpan dalam 4 byte memori itu dari0, 0, 0, 1
menjadi0, 0, 0, 2
. Jika ada variabel int lain di tempat lain, ia memiliki 4 byte sendiri.Variabel dalam bahasa seperti Python adalah nama untuk objek yang memiliki kehidupan sendiri. Ada objek untuk nomor tersebut
1
, dan objek lain untuk nomor tersebut2
. Dana
bukan 4 byte memori yang direpresentasikan sebagaiint
, itu hanya nama yang menunjuk1
objek. Tidak masuk akal untuka = 2
mengubah angka 1 menjadi angka 2 (yang akan memberi programmer Python cara terlalu banyak kekuatan untuk mengubah cara kerja fundamental alam semesta); apa yang dilakukan sebagai gantinya adalah hanya membuata
melupakan1
objek dan menunjuk2
objek sebagai gantinya.Jadi, jika tugas bukan mutasi, apa itu mutasi?
a.append(b)
. (Perhatikan bahwa metode ini hampir selalu kembaliNone
). Tipe yang tidak berubah tidak memiliki metode seperti itu, tipe yang bisa berubah biasanya.a.spam = b
ataua[0] = b
. Tipe yang tidak dapat diubah tidak memungkinkan penugasan ke atribut atau elemen, tipe yang dapat berubah biasanya memungkinkan satu atau yang lain.a += b
, terkadang tidak. Jenis yang dapat berubah biasanya memutasi nilai; tipe yang tidak dapat diubah tidak pernah melakukannya, dan sebaliknya memberikan Anda salinan (mereka menghitunga + b
, kemudian menetapkan hasilnyaa
).Tetapi jika penugasan bukan mutasi, bagaimana penugasan ke bagian dari mutasi objek? Di situlah rumit.
a[0] = b
tidak tidak bermutasia[0]
(sekali lagi, tidak seperti C ++), tetapi tidak bermutasia
(tidak seperti C ++, kecuali secara tidak langsung).Semua ini adalah alasan mengapa mungkin lebih baik untuk tidak mencoba menempatkan semantik Python dalam hal bahasa yang biasa Anda gunakan, dan sebaliknya belajar semantik Python dengan istilah mereka sendiri.
sumber
Apakah suatu objek bisa berubah atau tidak tergantung pada tipenya. Ini tidak tergantung pada apakah ia memiliki metode tertentu atau tidak, pada struktur hierarki kelas.
Jenis yang ditentukan pengguna (yaitu kelas) umumnya bisa berubah. Ada beberapa pengecualian, seperti sub-kelas sederhana dari tipe yang tidak dapat diubah. Jenis kekal lainnya termasuk beberapa built-in jenis seperti
int
,float
,tuple
danstr
, serta beberapa kelas Python diimplementasikan dalam C.Penjelasan umum dari bab "Model Data" dalam Referensi Bahasa Python " :
sumber
Perbedaan antara benda yang dapat Berubah dan yang Tidak Berubah
Definisi
Objek bisa berubah : Obyek yang dapat diubah setelah menciptakan itu.
Objek abadi : Obyek yang tidak dapat diubah setelah menciptakan itu.
Dalam python jika Anda mengubah nilai objek yang tidak dapat diubah itu akan membuat objek baru.
Objek yang Dapat Diubah
Berikut adalah objek dalam Python yang bertipe bisa berubah:
list
Dictionary
Set
bytearray
user defined classes
Objek yang Tidak Berubah
Berikut adalah objek dalam Python yang bertipe tidak berubah:
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
Beberapa Pertanyaan Tidak Terjawab
Pertanyaan : Apakah string merupakan tipe yang tidak dapat diubah?
Jawab : ya , tapi bisakah Anda menjelaskan ini: Bukti 1 :
Keluaran
Dalam contoh di atas string yang pernah dibuat sebagai "Hello" kemudian berubah menjadi "Hello World". Ini menyiratkan bahwa string adalah tipe yang bisa berubah. Tapi itu bukan ketika kita memeriksa identitasnya untuk melihat apakah itu jenis yang bisa berubah atau tidak.
Keluaran
Bukti 2 :
Keluaran
Pertanyaan : Apakah Tuple adalah tipe yang tidak berubah?
Jawab : ya , benar. Bukti 1 :
Keluaran
sumber
Objek yang dapat berubah harus memiliki setidaknya metode yang dapat mengubah objek. Misalnya,
list
objek memilikiappend
metode, yang akan benar-benar bermutasi objek:tetapi kelas
float
tidak memiliki metode untuk bermutasi objek float. Anda dapat melakukan:tetapi
=
operan bukan metode. Itu hanya membuat ikatan antara variabel dan apa pun di sebelah kanan itu, tidak ada yang lain. Itu tidak pernah mengubah atau membuat objek. Ini adalah pernyataan tentang apa yang akan ditunjukkan oleh variabel, sejak sekarang.Ketika Anda melakukan
b = b + 0.1
itu=
operan mengikat variabel untuk float baru, yang secara dibuat dengan te hasil5 + 0.1
.Ketika Anda menetapkan variabel ke objek yang ada, bisa berubah atau tidak,
=
operan mengikat variabel ke objek itu. Dan tidak ada lagi yang terjadiDalam kedua kasus,
=
hanya membuat ikatan. Itu tidak mengubah atau membuat objek.Ketika Anda melakukannya
a = 1.0
,=
operan tidak menciptakan float, tetapi1.0
bagian dari garis. Sebenarnya ketika Anda menulis1.0
itu adalah singkatan untukfloat(1.0)
panggilan konstruktor mengembalikan objek float. (Itulah alasan mengapa jika Anda mengetik1.0
dan menekan enter Anda mendapatkan "gema" yang1.0
dicetak di bawah ini; itu adalah nilai pengembalian fungsi konstruktor yang Anda panggil)Sekarang, jika
b
adalah pelampung dan Anda menetapkana = b
, kedua variabel yang menunjuk ke objek yang sama, namun sebenarnya variabel tidak bisa comunicate betweem sendiri, karena benda tersebut inmutable, dan jika Anda melakukannyab += 1
, sekarangb
arahkan ke objek baru, dana
adalah masih menunjuk ke yang lama dan tidak bisa tahu apab
yang menunjuk.tetapi jika
c
, katakanlah, alist
, dan Anda tetapkana = c
, sekaranga
danc
dapat "berkomunikasi", karenalist
bisa berubah, dan jika Anda melakukannyac.append('msg')
, maka cukup memeriksaa
Anda mendapatkan pesan.(Omong-omong, setiap objek memiliki nomor id unik yang dikaitkan, yang dapat Anda peroleh
id(x)
. Jadi, Anda dapat memeriksa apakah suatu objek sama atau tidak memeriksa apakah id uniknya telah berubah.)sumber
Dengan kata lain ubah seluruh nilai variabel itu
(name)
atau biarkan saja.Contoh:
Anda mengharapkan ini berfungsi dan mencetak hello world tetapi ini akan menimbulkan kesalahan berikut:
Penerjemah mengatakan: saya tidak dapat mengubah karakter pertama dari string ini
Anda harus mengubah keseluruhan
string
untuk membuatnya bekerja:periksa tabel ini:
sumber
sumber
my_string = 'h' + my_string[1:]
. Ini akan menghasilkan string baru yang disebut my_string, dan my_string asli hilang (cetakid(my_string)
untuk melihat ini). Tentu saja itu tidak terlalu fleksibel, untuk kasus yang lebih umum Anda dapat mengkonversi ke daftar dan kembali:l = list(my_string)
l[0] = 'h'
my_string = ''.join(l)
Tampaknya bagi saya bahwa Anda bertengkar dengan pertanyaan apa yang sebenarnya bisa berubah / tidak berubah . Jadi, inilah penjelasan sederhana:
Pertama-tama kita membutuhkan landasan untuk mendasarkan eksplorasi.
Jadi pikirkan apa pun yang Anda program sebagai objek virtual, sesuatu yang disimpan dalam memori komputer sebagai urutan angka biner. (Namun, jangan mencoba membayangkan ini terlalu keras. ^^) Sekarang di sebagian besar bahasa komputer Anda tidak akan bekerja dengan angka-angka biner ini secara langsung, tetapi lebih Anda menggunakan interpretasi angka-angka biner.
Misalnya Anda tidak berpikir tentang angka seperti 0x110, 0xaf0278297319 atau serupa, tetapi Anda berpikir tentang angka seperti 6 atau String seperti "Halo, dunia". Tidak pernah kurang angka-angka tesis atau String adalah interpretasi dari angka biner dalam memori komputer. Hal yang sama berlaku untuk nilai variabel apa pun.
Singkatnya: Kami tidak memprogram dengan nilai aktual tetapi dengan interpretasi dari nilai biner aktual.
Sekarang kita memiliki interpretasi yang tidak boleh diubah demi logika dan "hal-hal rapi" lainnya sementara ada interpretasi yang mungkin dapat diubah. Misalnya pikirkan simulasi kota, dengan kata lain program di mana ada banyak objek virtual dan beberapa di antaranya adalah rumah. Sekarang mungkinkah benda-benda virtual ini (rumah-rumah) diubah dan masihkah mereka dapat dianggap sebagai rumah yang sama? Ya tentu saja mereka bisa. Dengan demikian mereka bisa berubah: Mereka dapat diubah tanpa menjadi objek yang "sepenuhnya" berbeda.
Sekarang pikirkan bilangan bulat: Ini juga adalah objek virtual (urutan angka biner dalam memori komputer). Jadi jika kita mengubah salah satunya, seperti menambah nilai enam per satu, apakah masih enam? Ya tentu saja tidak. Jadi bilangan bulat apa pun tidak dapat berubah.
Jadi: Jika ada perubahan pada objek virtual berarti bahwa itu benar-benar menjadi objek virtual lain, maka itu disebut abadi.
Komentar akhir:
(1) Jangan pernah mencampurkan pengalaman dunia nyata Anda yang bisa berubah dan tidak berubah dengan pemrograman dalam bahasa tertentu:
Setiap bahasa pemrograman memiliki definisi sendiri di mana objek dapat dimatikan dan yang tidak.
Jadi sementara Anda sekarang dapat memahami perbedaan makna, Anda masih harus mempelajari implementasi aktual untuk setiap bahasa pemrograman. ... Memang mungkin ada tujuan dari bahasa di mana angka 6 dapat diredam untuk menjadi angka 7. Kemudian lagi ini akan menjadi hal yang cukup gila atau menarik, seperti simulasi alam semesta paralel. ^^
(2) Penjelasan ini tentu saja tidak ilmiah, ini dimaksudkan untuk membantu Anda memahami perbedaan antara bisa berubah dan tidak berubah.
sumber
Tujuan dari jawaban ini adalah untuk menciptakan satu tempat untuk menemukan semua ide bagus tentang bagaimana cara mengetahui apakah Anda berurusan dengan mutasi / nonmutasi (tidak berubah / tidak bisa berubah), dan jika mungkin, apa yang harus dilakukan? Ada saat-saat ketika mutasi tidak diinginkan dan perilaku python dalam hal ini bisa terasa kontra-intuitif untuk coders yang datang dari bahasa lain.
Per posting yang bermanfaat oleh @ mina-gabriel:
Menganalisis di atas dan menggabungkan dengan posting oleh @ arrakëën:
Apa yang tidak bisa berubah secara tak terduga?
Apa yang bisa?
oleh "tiba-tiba" Maksud saya programmer dari bahasa lain mungkin tidak mengharapkan perilaku ini (dengan pengecualian atau Ruby, dan mungkin beberapa bahasa "Python like" lainnya).
Menambah diskusi ini:
Perilaku ini merupakan keuntungan ketika mencegah Anda secara tidak sengaja mengisi kode Anda dengan banyak salinan struktur data besar yang memakan memori. Tetapi ketika ini tidak diinginkan, bagaimana kita mengatasinya?
Dengan daftar, solusi sederhana adalah membangun yang baru seperti ini:
list2 = daftar (list1)
dengan struktur lain ... solusinya bisa lebih sulit. Salah satu caranya adalah dengan loop melalui elemen dan menambahkannya ke struktur data kosong baru (dari tipe yang sama).
fungsi dapat bermutasi yang asli ketika Anda lulus dalam struktur yang bisa berubah. Bagaimana cara mengatakannya?
Pendekatan Non-standar (dalam hal membantu): Menemukan ini di github yang diterbitkan di bawah lisensi MIT:
Untuk kelas khusus, @semicolon menyarankan untuk memeriksa apakah ada
__hash__
fungsi karena objek yang bisa berubah biasanya tidak memiliki__hash__()
fungsi.Ini semua yang telah saya kumpulkan tentang topik ini untuk saat ini. Ide lain, koreksi, dll. Dipersilakan. Terima kasih.
sumber
Salah satu cara berpikir tentang perbedaan:
Penugasan ke objek yang tidak dapat diubah dalam python dapat dianggap sebagai salinan yang dalam, sedangkan penugasan ke objek yang tidak dapat diubah adalah dangkal
sumber
Jawaban paling sederhana:
Variabel yang dapat berubah adalah variabel yang nilainya dapat berubah pada tempatnya, sedangkan dalam variabel yang tidak berubah, perubahan nilai tidak akan terjadi pada tempatnya. Mengubah variabel yang tidak dapat diubah akan membangun kembali variabel yang sama.
Contoh:
Akan membuat nilai 5 direferensikan oleh x
x -> 5
Pernyataan ini akan membuat Anda merujuk ke 5 x
x -------------> 5 <----------- y
Seperti x menjadi bilangan bulat (tipe tidak berubah) telah dibangun kembali.
Dalam pernyataan itu, ekspresi pada RHS akan menghasilkan nilai 10 dan ketika ini ditugaskan ke LHS (x), x akan dibangun kembali menjadi 10. Jadi sekarang
x ---------> 10
y ---------> 5
sumber
Saya belum membaca semua jawaban, tetapi jawaban yang dipilih tidak benar dan saya pikir penulis memiliki gagasan bahwa dapat menetapkan ulang suatu variabel berarti bahwa apa pun jenis data yang bisa berubah. Bukan itu masalahnya. Mutabilitas berkaitan dengan melewati dengan referensi daripada melewati dengan nilai.
Katakanlah Anda membuat Daftar
Jika Anda mengatakan:
Meskipun Anda menetapkan ulang nilai pada B, itu juga akan menetapkan kembali nilai pada a. Itu karena ketika Anda menetapkan "b = a". Anda memberikan "Referensi" ke objek daripada salinan nilainya. Ini bukan kasus dengan string, float dll. Ini membuat daftar, kamus dan sejenisnya bisa berubah, tetapi booleans, floats dll tidak berubah.
sumber
Untuk objek yang tidak berubah, tugas membuat salinan nilai baru, misalnya.
Untuk objek yang bisa diubah, tugas tidak membuat salinan nilai lain. Sebagai contoh,
sumber
x=10
hanyalah tugas lain , saatx[2] = 5
memanggil metode mutator.int
objek tidak memiliki metode mutator , tetapi semantik penugasan python tidak tergantung pada jenisnyaDengan Python, ada cara mudah untuk mengetahui:
Kekal:
Yg mungkin berubah:
Dan:
Jadi saya pikir fungsi bawaan juga tidak berubah dalam Python.
Tapi saya benar-benar tidak mengerti cara kerja float:
Ini sangat aneh.
sumber
x = (1, 2)
lalu coba dan mutasix
, itu tidak mungkin. Salah satu cara yang saya temukan untuk memeriksa mutabilitas adalahhash
, ia berfungsi setidaknya untuk objek bawaan.hash(1)
hash('a')
hash((1, 2))
hash(True)
semua bekerja, danhash([])
hash({})
hash({1, 2})
semua tidak bekerja.hash()
akan bekerja jika objek mendefinisikan__hash__()
metode, meskipun kelas yang ditentukan pengguna umumnya dapat berubah.hash
metode ini masih cukup bagus, karena objek yang bisa berubah umumnya tidak memiliki__hash__()
metode, karena membuat mereka kunci dalam kamus hanya berbahaya.