Tipe Immutable vs Mutable

186

Saya bingung tentang tipe yang tidak bisa diubah. Saya tahu floatobjek 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 floatada di bagian atas kelas dan merupakan pemanggilan metodenya sendiri. Mirip dengan jenis contoh ini (meskipun buku saya mengatakan dictbisa 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 examplemetode, itu mengembalikan kamus. The SortedKeyDictdengan __new__bendera itu sebagai kesalahan. Saya mencoba meneruskan bilangan bulat ke RoundFloatkelas __new__dan ditandai tidak ada kesalahan.

pengguna1027217
sumber
Anda juga dapat memeriksa tugas Daftar dengan [:] dan python kapan harus menggunakan copy.copy yang juga saya jawab untuk info lebih lanjut tentang mutabilitas.
Agustus

Jawaban:

232

Apa? Mengapung tidak berubah? Tapi aku tidak bisa

x = 5.0
x += 7.0
print x # 12.0

Bukankah itu "mut" x?

Yah Anda setuju string tidak bisa diubah kan? Tetapi Anda dapat melakukan hal yang sama.

s = 'foo'
s += 'bar'
print s # foobar

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.

x = something # immutable type
print x
func(x)
print x # prints the same thing

x = something # mutable type
print x
func(x)
print x # might print something different

x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing

x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different

Contoh nyata

x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo

x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]

def func(val):
    val += 'bar'

x = 'foo'
print x # foo
func(x)
print x # foo

def func(val):
    val += [3, 2, 1]

x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]
Bintang fajar
sumber
5
Apa yang Anda jelaskan artinya bagi saya: variabel yang dapat diubah dilewatkan dengan referensi, variabel yang tidak dapat diubah dilewatkan oleh nilai. Apakah ini benar ?
Lorenz Meyer
17
Hampir, tetapi tidak persis. Secara teknis, semua variabel dilewatkan dengan referensi dalam Python, tetapi memiliki semantik lebih seperti lulus dengan nilai dalam C. Contoh tandingan untuk analogi Anda adalah jika Anda melakukannya 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.
morningstar
6
Jenis yang bisa berubah dapat diubah di tempat. Jenis yang tidak dapat diubah tidak dapat berubah pada tempatnya. Itulah cara python melihat dunia. Ini terlepas dari bagaimana variabel diteruskan ke fungsi.
ychaouche
13
Perbedaan utama antara semantik Python dan semantik referensi referensi C ++ adalah bahwa penugasannya bukan mutasi dalam Python, dan itu adalah dalam C ++. (Tapi tentu saja itu rumit oleh fakta bahwa penambahan tugas, seperti a += bkadang - 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] = btidak bermutasi a[0], tetapi mungkin memang bermutasi a... 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 ...)
abarnert
2
Saya menemukan jawaban ini menyesatkan karena tidak menggunakan id (), yang sangat penting untuk memahami apa artinya abadi.
pawel_winzig
185

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 TypeErrorjika Anda mencoba mengubahnya. Juga, jika kami menetapkan konten baru, objek baru dibuat alih-alih konten yang dimodifikasi.

>>> s = "abc"
>>>id(s)
4702124
>>> s[0] 
'a'
>>> s[0] = "o"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>>id(s)
4800100
>>> s += "uvw"
>>>id(s)
4800500

Anda dapat melakukannya dengan daftar dan itu tidak akan mengubah identitas objek

>>> i = [1,2,3]
>>>id(i)
2146718700
>>> i[0] 
1
>>> i[0] = 7
>>> id(i)
2146718700

Untuk membaca lebih lanjut tentang model data Python, Anda bisa melihat referensi bahasa Python:

sebs
sumber
4
+1 Untuk tautan ke dokumen Python. Namun saya butuh waktu sampai saya menyadari bahwa hari ini Anda perlu membedakan antara Python 2 & 3 - Saya memperbarui jawaban untuk menekankan itu.
benjamin
107

Jenis abadi yang umum:

  1. nomor: int(), float(),complex()
  2. urutan berubah: str(), tuple(), frozenset(),bytes()

Jenis yang bisa berubah-ubah (hampir semuanya):

  1. urutan bisa berubah: list(),bytearray()
  2. jenis yang ditetapkan: set()
  3. jenis pemetaan: dict()
  4. kelas, instance kelas
  5. dll.

Salah satu trik untuk dengan cepat menguji apakah suatu tipe bisa berubah atau tidak, adalah dengan menggunakan id()fungsi bawaan.

Contohnya, menggunakan pada integer,

>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)

menggunakan daftar,

>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)
Spektral
sumber
11
Diterangkan dengan baik. Menyukai konsep memeriksa oleh id(). +1.
Parag Tyagi
4
Sebenarnya penggunaannya 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.
augurar
37

Pertama-tama, apakah suatu kelas memiliki metode atau apa struktur kelasnya tidak ada hubungannya dengan mutabilitas.

ints dan floats tidak berubah . Jika aku melakukan

a = 1
a += 5

Itu menunjuk nama adi suatu 1tempat di memori di baris pertama. Pada baris kedua, terlihat up yang 1, menambahkan 5, mendapat 6, maka poin apada saat itu 6dalam memori - itu tidak mengubah yang 1ke 6cara apapun. Logika yang sama berlaku untuk contoh-contoh berikut, menggunakan tipe tidak berubah lainnya :

b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')

Untuk tipe yang bisa berubah , saya dapat melakukan hal yang secara aktual mengubah nilai penyimpanannya . Dengan:

d = [1, 2, 3]

Saya telah membuat daftar lokasi 1, 2dan 3di memori. Jika saya melakukannya

e = d

Saya hanya menunjuk eke poin yang samalist d di. Saya kemudian dapat melakukan:

e += [4, 5]

Dan daftar yang menunjuk edan dakan diperbarui juga memiliki lokasi 4dan 5dalam memori.

Jika saya kembali ke tipe yang tidak dapat diubah dan melakukannya dengan tuple:

f = (1, 2, 3)
g = f
g += (4, 5)

Maka fmasih hanya menunjuk ke aslinyatuple - Anda telah menunjuk gpada yang sama sekali barutuple .

Sekarang, dengan contoh Anda

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

Di mana Anda lulus

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

(yang merupakan tupledari tuples) sebagai val, Anda mendapatkan kesalahan karena tuples tidak memiliki .clear()metode - Anda harus lulus dict(d)sebagai valuntuk itu untuk bekerja, dalam hal ini Anda akan mendapatkan kosong SortedKeyDictsebagai hasilnya.

agf
sumber
2
Ini penjelasan yang sangat bagus. Sangat menyukai pertanyaan ini dan banyak perspektif (baru) yang menarik untuk menjelaskannya.
Failed Scientist
25

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:

>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!

Dalam Python, tugas bukanlah mutasi dalam Python.

Di C ++, jika Anda menulis a = 2, Anda menelepon a.operator=(2), yang akan mengubah objek yang disimpan a. (Dan jika ada itu tidak ada objek yang disimpan dalam a, itu kesalahan.)

Dalam Python, a = 2tidak melakukan apa pun untuk apa pun yang disimpan di a; itu hanya berarti bahwa 2sekarang disimpan asebagai gantinya. (Dan jika ada yang tidak ada objek yang disimpan dalam a, 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 aadalah int, itu berarti 4 byte di suatu tempat yang diketahui oleh kompiler seharusnya ditafsirkan sebagai int. Jadi, ketika Anda melakukannya a = 2, itu mengubah apa yang disimpan dalam 4 byte memori itu dari 0, 0, 0, 1menjadi 0, 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 tersebut 2. Dan abukan 4 byte memori yang direpresentasikan sebagai int, itu hanya nama yang menunjuk 1objek. Tidak masuk akal untuk a = 2mengubah 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 membuat amelupakan 1objek dan menunjuk 2objek sebagai gantinya.


Jadi, jika tugas bukan mutasi, apa itu mutasi?

  • Memanggil metode yang didokumentasikan untuk bermutasi, seperti a.append(b). (Perhatikan bahwa metode ini hampir selalu kembali None). Tipe yang tidak berubah tidak memiliki metode seperti itu, tipe yang bisa berubah biasanya.
  • Menetapkan ke bagian objek, seperti a.spam = batau a[0] = b. Tipe yang tidak dapat diubah tidak memungkinkan penugasan ke atribut atau elemen, tipe yang dapat berubah biasanya memungkinkan satu atau yang lain.
  • Terkadang menggunakan penugasan augmented, seperti 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 menghitung a + b, kemudian menetapkan hasilnya a).

Tetapi jika penugasan bukan mutasi, bagaimana penugasan ke bagian dari mutasi objek? Di situlah rumit. a[0] = btidak tidak bermutasi a[0](sekali lagi, tidak seperti C ++), tetapi tidak bermutasi a(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.

abarnert
sumber
2
Katakan a = 'hai'. a [0] = 'f' akan memiliki 'mencetak' cetak 'fi' (Apakah saya sejauh ini?), jadi ketika Anda mengatakan bahwa itu tidak bermutasi [0], lebih tepatnya a, apa artinya itu ? Apakah [n] juga memiliki tempatnya sendiri sekarang, dan mengubah nilainya mengarahkannya ke nilai yang berbeda?
Daniel Springer
19

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, tupledanstr , serta beberapa kelas Python diimplementasikan dalam C.

Penjelasan umum dari bab "Model Data" dalam Referensi Bahasa Python " :

Nilai beberapa objek dapat berubah. Objek yang nilainya dapat berubah dikatakan bisa berubah; objek yang nilainya tidak dapat diubah begitu mereka dibuat disebut tidak berubah.

(Nilai objek kontainer tidak berubah yang berisi referensi ke objek bisa berubah dapat berubah ketika nilai terakhir berubah; namun wadah masih dianggap tidak berubah, karena koleksi objek yang dikandungnya tidak dapat diubah. Jadi, ketidakmampuan tidak sepenuhnya ketat sama seperti memiliki nilai yang tidak dapat diubah, itu lebih halus.)

Mutabilitas suatu objek ditentukan oleh tipenya; misalnya, angka, string, dan tupel tidak berubah, sedangkan kamus dan daftar bisa berubah.

taleinat
sumber
+1 Namun perlu dicatat bahwa hanya beberapa jenis ekstensi (Anda mungkin ingin meninjau definisi Anda tentang itu, semua jenis bawaan Python diimplementasikan dalam C) tidak dapat diubah. Lainnya (kebanyakan, saya berani katakan) bisa berubah-ubah.
@delnan Apa yang Anda sebut "tipe ekstensi" ?
eyquem
@eyquem: Saya menggunakan istilah "tipe ekstensi" dengan tidak benar dalam jawaban saya, dan delnan mengacu pada itu. Setelah komentarnya, saya merevisi jawaban saya dan menghindari menggunakan istilah ini.
taleinat
19

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:

  1. list
  2. Dictionary
  3. Set
  4. bytearray
  5. user defined classes

Objek yang Tidak Berubah

Berikut adalah objek dalam Python yang bertipe tidak berubah:

  1. int
  2. float
  3. decimal
  4. complex
  5. bool
  6. string
  7. tuple
  8. range
  9. frozenset
  10. bytes

Beberapa Pertanyaan Tidak Terjawab

Pertanyaan : Apakah string merupakan tipe yang tidak dapat diubah?
Jawab : ya , tapi bisakah Anda menjelaskan ini: Bukti 1 :

a = "Hello"
a +=" World"
print a

Keluaran

"Hello World"

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.

a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
    print "String is Immutable"

Keluaran

String is Immutable

Bukti 2 :

a = "Hello World"
a[0] = "M"

Keluaran

TypeError 'str' object does not support item assignment

Pertanyaan : Apakah Tuple adalah tipe yang tidak berubah?
Jawab : ya , benar. Bukti 1 :

tuple_a = (1,)
tuple_a[0] = (2,)
print a

Keluaran

'tuple' object does not support item assignment
anand tripathi
sumber
In [46]: a = "Hello" In [47]: id (a) Out [47]: 140071263880128 In [48]: a = a.replace ("H", "g") In [49]: a Keluar [49]: 'gello' Masuk [50]: id (a) Keluar [50]: 140071263881040
Argus Malware
apakah Anda mau membuktikan masalah penugasan item Anda ke contoh yang saya berikan di atas
Argus Malware
penugasan item tidak menjadi masalah dalam tipe yang tidak dapat diubah. Dalam kasus Anda, Anda mengubah string tetapi dalam memori penugasannya ke variabel baru. Penugasan item dalam kasus saya tidak akan mengubah memori variabel seperti dalam kasus daftar atau kamus. jika Anda melakukan penggantian, Anda membuat variabel baru yang tidak mengubah variabel yang ada
anand tripathi
@ ArgusMalware dalam kasus Anda, dua id sama dengan yang pertama didaur ulang oleh GC, sehingga yang kedua menggunakan kembali memori.
Cologler
11

Objek yang dapat berubah harus memiliki setidaknya metode yang dapat mengubah objek. Misalnya, listobjek memiliki appendmetode, yang akan benar-benar bermutasi objek:

>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']

tetapi kelas floattidak memiliki metode untuk bermutasi objek float. Anda dapat melakukan:

>>> b = 5.0 
>>> b = b + 0.1
>>> b
5.1

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.1itu =operan mengikat variabel untuk float baru, yang secara dibuat dengan te hasil 5 + 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 terjadi

Dalam kedua kasus, =hanya membuat ikatan. Itu tidak mengubah atau membuat objek.

Ketika Anda melakukannya a = 1.0, =operan tidak menciptakan float, tetapi 1.0bagian dari garis. Sebenarnya ketika Anda menulis 1.0itu adalah singkatan untuk float(1.0)panggilan konstruktor mengembalikan objek float. (Itulah alasan mengapa jika Anda mengetik 1.0dan menekan enter Anda mendapatkan "gema" yang 1.0dicetak di bawah ini; itu adalah nilai pengembalian fungsi konstruktor yang Anda panggil)

Sekarang, jika badalah pelampung dan Anda menetapkan a = b, kedua variabel yang menunjuk ke objek yang sama, namun sebenarnya variabel tidak bisa comunicate betweem sendiri, karena benda tersebut inmutable, dan jika Anda melakukannya b += 1, sekarang barahkan ke objek baru, dan aadalah masih menunjuk ke yang lama dan tidak bisa tahu apa byang menunjuk.

tetapi jika c, katakanlah, a list, dan Anda tetapkan a = c, sekarang adan cdapat "berkomunikasi", karena listbisa berubah, dan jika Anda melakukannya c.append('msg'), maka cukup memeriksa aAnda 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.)

nadapez
sumber
6

Sebuah kelas berubah jika setiap objek dari kelas yang memiliki nilai tetap pada Instansiasi yang tidak dapat kemudian diubah

Dengan kata lain ubah seluruh nilai variabel itu (name)atau biarkan saja.

Contoh:

my_string = "Hello world" 
my_string[0] = "h"
print my_string 

Anda mengharapkan ini berfungsi dan mencetak hello world tetapi ini akan menimbulkan kesalahan berikut:

Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment

Penerjemah mengatakan: saya tidak dapat mengubah karakter pertama dari string ini

Anda harus mengubah keseluruhan stringuntuk membuatnya bekerja:

my_string = "Hello World" 
my_string = "hello world"
print my_string #hello world

periksa tabel ini:

masukkan deskripsi gambar di sini

sumber

Mina Gabriel
sumber
Bagaimana seseorang dapat memodifikasi komponen string python dengan cara yang lebih ringkas daripada yang Anda tunjukkan di atas?
Luke Davis
@LukeDavis Anda bisa melakukannya my_string = 'h' + my_string[1:]. Ini akan menghasilkan string baru yang disebut my_string, dan my_string asli hilang (cetak id(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)
danio
5

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.

Markus Alpers
sumber
5

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?

  • skalar (tipe variabel yang menyimpan nilai tunggal) tidak berubah secara tak terduga
    • contoh numerik: int (), float (), complex ()
  • ada beberapa "urutan yang bisa berubah-ubah":
    • str (), tuple (), frozenset (), bytes ()

Apa yang bisa?

  • daftar seperti objek (daftar, kamus, set, bytearray ())
  • sebuah posting di sini juga mengatakan kelas dan instance kelas tetapi ini mungkin tergantung pada apa yang diwarisi dari kelas dan / atau bagaimana dibangunnya.

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?

  • Ada beberapa tes yang diberikan pada komentar lain di utas ini tetapi kemudian ada komentar yang menunjukkan tes ini bukan bukti lengkap
  • object.function () adalah metode dari objek asli tetapi hanya beberapa di antaranya bermutasi. Jika mereka tidak mengembalikan apa pun, mereka mungkin melakukannya. Orang akan mengharapkan. Append () untuk bermutasi tanpa mengujinya diberi namanya. .union () mengembalikan penyatuan set1.union (set2) dan tidak bermutasi. Jika ragu, fungsi tersebut dapat diperiksa untuk nilai kembali. Jika return = None, itu tidak bermutasi.
  • diurutkan () mungkin merupakan solusi dalam beberapa kasus. Karena mengembalikan versi asli yang diurutkan, ini dapat memungkinkan Anda untuk menyimpan salinan yang tidak bermutasi sebelum Anda mulai mengerjakan yang asli dengan cara lain. Namun, opsi ini mengasumsikan Anda tidak peduli dengan urutan elemen asli (jika ya, Anda perlu mencari cara lain). Sebaliknya .sort () bermutasi asli (seperti yang mungkin diharapkan).

Pendekatan Non-standar (dalam hal membantu): Menemukan ini di github yang diterbitkan di bawah lisensi MIT:

  • repositori github di bawah: tobgu bernama: pyrsistent
  • Apa itu: Python kode struktur data persisten ditulis untuk digunakan sebagai pengganti struktur data inti ketika mutasi tidak diinginkan

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.

TMWP
sumber
3

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

Aditya Sihag
sumber
1
Ini salah. Semua tugas dengan Python adalah dengan referensi. Tidak ada penyalinan yang terlibat.
augurar
3

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:

>>>x = 5

Akan membuat nilai 5 direferensikan oleh x

x -> 5

>>>y = x

Pernyataan ini akan membuat Anda merujuk ke 5 x

x -------------> 5 <----------- y

>>>x = x + 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

Amit Upadhyay
sumber
-1

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

a = [1,2]

Jika Anda mengatakan:

b = a
b[1] = 3

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.

Scott
sumber
-1

Untuk objek yang tidak berubah, tugas membuat salinan nilai baru, misalnya.

x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot 
#effect the value of y
print(x,y)

Untuk objek yang bisa diubah, tugas tidak membuat salinan nilai lain. Sebagai contoh,

x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy 
x[2]=5
print(x,y) # both x&y holds the same list
Ravi Gurnatham
sumber
1
Benar-benar salah. Tugas tidak pernah membuat salinan . Silakan baca nedbatchelder.com/text/names.html Dalam kasus pertama, x=10hanyalah tugas lain , saat x[2] = 5memanggil metode mutator. intobjek tidak memiliki metode mutator , tetapi semantik penugasan python tidak tergantung pada jenisnya
juanpa.arrivillaga
-2

Dengan Python, ada cara mudah untuk mengetahui:

Kekal:

    >>> s='asd'
    >>> s is 'asd'
    True
    >>> s=None
    >>> s is None
    True
    >>> s=123
    >>> s is 123
    True

Yg mungkin berubah:

>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False

Dan:

>>> s=abs
>>> s is abs
True

Jadi saya pikir fungsi bawaan juga tidak berubah dalam Python.

Tapi saya benar-benar tidak mengerti cara kerja float:

>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256

Ini sangat aneh.

Jason Yan
sumber
Tapi itu jelas tidak valid. Karena tuple tidak berubah. Ketik x = (1, 2)lalu coba dan mutasi x, itu tidak mungkin. Salah satu cara yang saya temukan untuk memeriksa mutabilitas adalah hash, ia berfungsi setidaknya untuk objek bawaan. hash(1) hash('a') hash((1, 2)) hash(True)semua bekerja, dan hash([]) hash({}) hash({1, 2})semua tidak bekerja.
titik koma
@semicolon Untuk kelas yang ditentukan pengguna kemudian hash()akan bekerja jika objek mendefinisikan __hash__()metode, meskipun kelas yang ditentukan pengguna umumnya dapat berubah.
augurar
1
@ augurar maksud saya ya, tapi tidak ada dalam Python yang akan menjamin apa pun, karena Python tidak memiliki pengetikan statis atau jaminan formal. Tetapi hashmetode ini masih cukup bagus, karena objek yang bisa berubah umumnya tidak memiliki __hash__()metode, karena membuat mereka kunci dalam kamus hanya berbahaya.
titik koma
1
@ augurar dan titik koma (atau yang lain jika mereka mengetahuinya): __hash __ () solusi ... apakah pencipta kelas kustom harus menambahkannya agar ada di sana? Jika demikian, maka aturannya adalah jika ada objek harus tidak berubah; jika tidak ada, kami tidak dapat memberi tahu karena pencipta mungkin hanya meninggalkan jika tidak aktif.
TMWP