Yang saya inginkan adalah perilaku ini:
class a:
list = []
x = a()
y = a()
x.list.append(1)
y.list.append(2)
x.list.append(3)
y.list.append(4)
print(x.list) # prints [1, 3]
print(y.list) # prints [2, 4]
Tentu saja, apa yang sebenarnya terjadi ketika saya mencetak adalah:
print(x.list) # prints [1, 2, 3, 4]
print(y.list) # prints [1, 2, 3, 4]
Jelas mereka membagikan data di kelas a
. Bagaimana saya mendapatkan contoh terpisah untuk mencapai perilaku yang saya inginkan?
list
sebagai nama atribut.list
adalah fungsi buil-in untuk membangun daftar baru. Anda harus menulis kelas nama dengan huruf besar.Jawaban:
Kamu mau ini:
Mendeklarasikan variabel di dalam deklarasi kelas menjadikannya "anggota" kelas dan bukan anggota instan. Mendeklarasikan mereka di dalam
__init__
metode memastikan bahwa instance baru dari anggota dibuat di samping setiap instance baru objek, yang merupakan perilaku yang Anda cari.sumber
x.list = []
, Anda bisa mengubahnya dan tidak memengaruhi orang lain. Masalah yang Anda hadapi adalah bahwax.list
dany.list
daftar yang sama, jadi ketika Anda memanggil menambahkan satu, itu mempengaruhi yang lain.__init__
.Jawaban yang diterima bekerja tetapi sedikit penjelasan tidak sakit.
Atribut kelas tidak menjadi atribut instance saat instance dibuat. Mereka menjadi atribut instan ketika nilai diberikan kepada mereka.
Dalam kode asli tidak ada nilai yang diberikan ke
list
atribut setelah instantiation; jadi itu tetap atribut kelas. Mendefinisikan daftar di dalam__init__
karya karena__init__
dipanggil setelah instantiation. Atau, kode ini juga akan menghasilkan output yang diinginkan:Namun, skenario yang membingungkan dalam pertanyaan tidak akan pernah terjadi pada objek yang tidak dapat diubah seperti angka dan string, karena nilainya tidak dapat diubah tanpa penugasan. Misalnya kode yang mirip dengan aslinya dengan tipe atribut string berfungsi tanpa masalah:
Jadi untuk meringkas: atribut kelas menjadi atribut instance jika dan hanya jika nilai diberikan kepada mereka setelah instantiation, sedang dalam
__init__
metode atau tidak . Ini adalah hal yang baik karena dengan cara ini Anda dapat memiliki atribut statis jika Anda tidak pernah menetapkan nilai ke atribut setelah instantiation.sumber
Anda menyatakan "daftar" sebagai "properti tingkat kelas" dan bukan "properti tingkat instance". Untuk memiliki properti yang dicakup pada tingkat instance, Anda perlu menginisialisasi mereka melalui referensi dengan parameter "mandiri" dalam
__init__
metode (atau di tempat lain tergantung pada situasinya).Anda tidak benar-benar harus menginisialisasi properti instance dalam
__init__
metode tetapi itu membuat lebih mudah dipahami.sumber
Meskipun jawaban yang diterima tepat, saya ingin menambahkan sedikit deskripsi.
Mari kita lakukan latihan kecil
pertama-tama tentukan kelas sebagai berikut:
Jadi apa yang kita miliki di sini?
temp
yang berupa string__init__
metode yang setself.x
self.temp
Cukup lurus ke depan sejauh ini ya? Sekarang mari kita mulai bermain-main dengan kelas ini. Mari kita inisialisasi kelas ini terlebih dahulu:
Sekarang lakukan hal berikut:
Yah,
a.temp
bekerja seperti yang diharapkan tetapi bagaimana sih ituA.temp
bekerja? Yah itu berhasil karena temp adalah atribut kelas. Segala sesuatu di python adalah objek. Di sini A juga merupakan objek kelastype
. Dengan demikian atribut temp adalah atribut yang dimiliki olehA
kelas dan jika Anda mengubah nilai temp melaluiA
(dan bukan melalui turunan daria
), nilai yang diubah akan tercermin dalam semua turunanA
kelas. Ayo maju dan lakukan itu:Menarik bukan? Dan perhatikan itu
id(a.temp)
danid(A.temp)
masih sama .Setiap objek Python secara otomatis diberikan
__dict__
atribut, yang berisi daftar atributnya. Mari selidiki apa isi kamus ini untuk objek contoh kami:Perhatikan bahwa
temp
atribut terdaftar di antaraA
atribut kelas sementarax
terdaftar untuk instance.Jadi bagaimana bisa kita mendapatkan nilai yang ditentukan
a.temp
jika bahkan tidak terdaftar sebagai contoha
. Nah itulah keajaiban__getattribute__()
metode. Dalam Python sintaksis putus-putus secara otomatis memanggil metode ini sehingga ketika kita menulisa.temp
, Python mengeksekusia.__getattribute__('temp')
. Metode itu melakukan tindakan pencarian atribut, yaitu menemukan nilai atribut dengan melihat di tempat yang berbeda.Implementasi standar
__getattribute__()
pencarian pertama kamus internal ( dikt ) dari suatu objek, kemudian jenis objek itu sendiri. Dalam hal inia.__getattribute__('temp')
dijalankan pertamaa.__dict__['temp']
dan kemudiana.__class__.__dict__['temp']
Oke sekarang mari kita gunakan
change
metode kami :Nah sekarang kita telah menggunakan
self
,print(a.temp)
memberi kita nilai berbedaprint(A.temp)
.Sekarang jika kita membandingkan
id(a.temp)
danid(A.temp)
, mereka akan berbeda.sumber
Ya, Anda harus mendeklarasikan dalam "konstruktor" jika Anda ingin daftar tersebut menjadi properti objek dan bukan properti kelas.
sumber
Jadi, hampir setiap respons di sini tampaknya melewatkan satu titik tertentu. Variabel kelas tidak pernah menjadi variabel instan seperti yang ditunjukkan oleh kode di bawah ini. Dengan menggunakan metaclass untuk mencegat penugasan variabel di tingkat kelas, kita dapat melihat bahwa ketika a.myattr dipindahkan, metode sihir penugasan bidang di kelas tidak dipanggil. Ini karena tugas membuat variabel instance baru . Perilaku ini sama sekali tidak ada hubungannya dengan variabel kelas seperti yang ditunjukkan oleh kelas kedua yang tidak memiliki variabel kelas dan masih memungkinkan penugasan lapangan.
DALAM SINGKAT variabel Kelas tidak ada hubungannya dengan variabel instan.
Lebih jelas. Mereka kebetulan berada dalam ruang lingkup untuk pencarian contoh. Variabel kelas sebenarnya adalah variabel instan pada objek kelas itu sendiri. Anda juga dapat memiliki variabel metaclass jika Anda mau juga karena metaclasses sendiri adalah objek juga. Semuanya adalah objek apakah itu digunakan untuk membuat objek lain atau tidak, jadi jangan terikat dalam semantik bahasa lain yang menggunakan kelas kata. Dalam python, sebuah kelas benar-benar hanya sebuah objek yang digunakan untuk menentukan cara membuat objek lain dan apa perilaku mereka nantinya. Metaclasses adalah kelas yang membuat kelas, hanya untuk menggambarkan hal ini lebih jauh.
sumber
Untuk melindungi variabel Anda yang dibagikan oleh instance lain, Anda perlu membuat variabel instance baru setiap kali Anda membuat instance. Saat Anda mendeklarasikan variabel di dalam kelas, itu adalah variabel kelas dan dibagikan oleh semua instance. Jika Anda ingin menjadikannya sebagai contoh, perlu menggunakan metode init untuk menginisialisasi ulang variabel seperti merujuk pada instance
Dari Objek dan Kelas Python oleh Programiz.com :
Sebagai contoh:
sumber