Apakah ada perbedaan yang berarti antara:
class A(object):
foo = 5 # some default value
vs.
class B(object):
def __init__(self, foo=5):
self.foo = foo
Jika Anda membuat banyak contoh, apakah ada perbedaan dalam kinerja atau persyaratan ruang untuk dua gaya? Ketika Anda membaca kode, apakah Anda menganggap arti dari kedua gaya tersebut sangat berbeda?
python
attributes
member-variables
Dan Homerick
sumber
sumber
Jawaban:
Di luar pertimbangan kinerja, ada perbedaan semantik yang signifikan . Dalam kasus atribut kelas, hanya ada satu objek yang dirujuk. Dalam instance-atribut-set-at-instantiation, mungkin ada beberapa objek yang dirujuk. Misalnya
sumber
int
danstr
mereka masih terikat dengan masing-masing instance daripada kelas.int
danstr
yang juga bersama, dengan cara yang persis sama. Anda dapat memeriksa dengan mudah denganis
atauid
. Atau lihat saja setiap instance__dict__
dan kelas__dict__
. Biasanya tidak terlalu menjadi masalah apakah tipe yang tidak dapat dibagi dibagikan atau tidak.a.foo = 5
, maka dalam kedua kasus Anda akan melihatb.foo
kembali[]
. Itu karena dalam kasus pertama, Anda menimpa atribut kelasa.foo
dengan atribut instance baru dengan nama yang sama.Perbedaannya adalah bahwa atribut pada kelas dibagi oleh semua instance. Atribut pada instance adalah unik untuk instance itu.
Jika berasal dari C ++, atribut pada kelas lebih seperti variabel anggota statis.
sumber
>>> class A(object): foo = 5
>>> a, b = A(), A()
>>> a.foo = 10
>>> b.foo
5
a.foo.append(5)
yang mengubah nilai yanga.foo
merujuk, sementaraa.foo = 5
membuata.foo
nama baru untuk nilai tersebut5
. Jadi, Anda berakhir dengan atribut instance yang menyembunyikan atribut class. Coba hal yang samaa.foo = 5
dalam versi Alex dan Anda akan melihat bahwab.foo
itu tidak berubah.Ini adalah posting yang sangat bagus , dan ringkasannya seperti di bawah ini.
Dan dalam bentuk visual
Penugasan atribut kelas
Jika atribut kelas diatur dengan mengakses kelas, itu akan menimpa nilai untuk semua instance
Jika variabel kelas diatur dengan mengakses sebuah instance, itu akan menimpa nilai hanya untuk instance itu . Ini pada dasarnya menimpa variabel kelas dan mengubahnya menjadi variabel instan yang tersedia, secara intuitif, hanya untuk instance tersebut .
Kapan Anda akan menggunakan atribut class?
Menyimpan konstanta . Karena atribut kelas dapat diakses sebagai atribut dari kelas itu sendiri, sering kali baik menggunakannya untuk menyimpan konstanta khusus kelas-lebar
Menentukan nilai default . Sebagai contoh sepele, kita dapat membuat daftar terbatas (yaitu, daftar yang hanya dapat menampung sejumlah elemen atau lebih sedikit) dan memilih untuk memiliki batas default 10 item
sumber
Karena orang-orang di komentar di sini dan di dua pertanyaan lain yang ditandai sebagai dups semuanya tampak bingung tentang hal ini dengan cara yang sama, saya pikir ada baiknya menambahkan jawaban tambahan di atas jawaban Alex Coventry .
Fakta bahwa Alex memberikan nilai dari tipe yang bisa berubah, seperti daftar, tidak ada hubungannya dengan apakah semuanya dibagikan atau tidak. Kita dapat melihat ini dengan
id
fungsi atauis
operator:(Jika Anda bertanya-tanya mengapa saya menggunakan
object()
alih-alih, katakanlah,5
itu untuk menghindari dua masalah lain yang sama sekali tidak ingin saya bahas di sini; karena dua alasan berbeda, sepenuhnya diciptakan secara terpisah5
dapat berakhir menjadi contoh nomor yang sama5
. Tapi seluruhnya dibuat secara terpisahobject()
tidak bisa.)Jadi, mengapa hal itu
a.foo.append(5)
dalam contoh Alex memengaruhib.foo
, tetapia.foo = 5
dalam contoh saya tidak? Nah, cobaa.foo = 5
dalam contoh Alex, dan perhatikan bahwa itu tidak mempengaruhi dib.foo
sana juga .a.foo = 5
hanya membuata.foo
menjadi nama untuk5
. Itu tidak mempengaruhib.foo
, atau nama lain untuk nilai lama yanga.foo
digunakan untuk merujuk. * Agak sulit bahwa kita membuat atribut instance yang menyembunyikan atribut kelas, ** tapi begitu Anda mendapatkannya, tidak ada yang rumit adalah terjadi di sini.Mudah-mudahan sekarang jelas mengapa Alex menggunakan daftar: fakta bahwa Anda dapat bermutasi daftar berarti lebih mudah untuk menunjukkan bahwa dua variabel nama daftar yang sama, dan juga berarti lebih penting dalam kode kehidupan nyata untuk mengetahui apakah Anda memiliki dua daftar atau dua nama untuk daftar yang sama.
* Kebingungan bagi orang-orang yang berasal dari bahasa seperti C ++ adalah bahwa dalam Python, nilai tidak disimpan dalam variabel. Nilai hidup di tanah nilai, sendiri, variabel hanya nama untuk nilai, dan tugas hanya membuat nama baru untuk nilai. Jika ini membantu, pikirkan setiap variabel Python sebagai
shared_ptr<T>
bukanT
.** Beberapa orang memanfaatkan ini dengan menggunakan atribut kelas sebagai "nilai default" untuk atribut instance yang instans mungkin atau mungkin tidak disetel. Ini bisa berguna dalam beberapa kasus, tetapi juga bisa membingungkan, jadi berhati-hatilah.
sumber
Ada satu situasi lagi.
Atribut class dan instance adalah Descriptor .
Di atas akan menampilkan:
Jenis akses instance yang sama melalui kelas atau instance mengembalikan hasil yang berbeda!
Dan saya menemukan definisi c.PyObject_GenericGetAttr, dan sebuah postingan yang bagus .
Menjelaskan
sumber