Saya melakukannya seperti:
def set_property(property,value):
def get_property(property):
atau
object.property = value
value = object.property
Saya baru mengenal Python, jadi saya masih menjelajahi sintaks, dan saya ingin saran untuk melakukan ini.
python
getter-setter
Jorge Guberte
sumber
sumber
._x
(yang bukan properti, hanya atribut biasa) memotongproperty
pembungkus. Hanya referensi untuk.x
melaluiproperty
.Cara "Pythonic" bukanlah menggunakan "getter" dan "setters", tetapi menggunakan atribut polos, seperti yang diperlihatkan oleh pertanyaan, dan
del
untuk menghapus (tetapi namanya diubah untuk melindungi yang tidak bersalah ... bawaan):Jika nanti, Anda ingin mengubah pengaturan dan mendapatkan, Anda dapat melakukannya tanpa harus mengubah kode pengguna, dengan menggunakan
property
dekorator:(Setiap dekorator menggunakan salinan dan memperbarui objek properti sebelumnya, jadi perhatikan bahwa Anda harus menggunakan nama yang sama untuk setiap set, mendapatkan, dan menghapus fungsi / metode.
Setelah mendefinisikan di atas, pengaturan asli, mendapatkan, dan menghapus kode adalah sama:
Anda harus menghindari ini:
Pertama, hal di atas tidak berfungsi, karena Anda tidak memberikan argumen untuk contoh bahwa properti akan diatur ke (biasanya
self
), yang akan menjadi:Kedua, ini menggandakan tujuan dari dua metode khusus,
__setattr__
dan__getattr__
.Ketiga, kami juga memiliki fungsi
setattr
dangetattr
builtin.The
@property
dekorator adalah untuk menciptakan getter dan setter.Misalnya, kita bisa mengubah perilaku pengaturan untuk menempatkan batasan nilai yang ditetapkan:
Secara umum, kami ingin menghindari menggunakan
property
dan hanya menggunakan atribut langsung.Inilah yang diharapkan oleh pengguna Python. Mengikuti aturan yang paling tidak mengejutkan, Anda harus mencoba memberikan apa yang mereka harapkan kepada pengguna kecuali Anda memiliki alasan yang sangat kuat untuk melakukan hal sebaliknya.
Demonstrasi
Misalnya, kami membutuhkan atribut objek yang kami lindungi untuk menjadi bilangan bulat antara 0 dan 100 inklusif, dan mencegah penghapusannya, dengan pesan yang sesuai untuk memberi tahu pengguna tentang penggunaannya yang benar:
(Catatan yang
__init__
mengacu padaself.protected_value
tetapi metode properti merujukself._protected_value
. Ini adalah agar__init__
menggunakan properti melalui API publik, memastikan itu "dilindungi".)Dan penggunaan:
Apakah nama itu penting?
Ya mereka lakukan .
.setter
dan.deleter
membuat salinan dari properti asli. Ini memungkinkan subclass untuk memodifikasi perilaku dengan benar tanpa mengubah perilaku pada induknya.Agar ini berfungsi, Anda harus menggunakan nama masing-masing:
Saya tidak yakin di mana ini akan berguna, tetapi kasus penggunaannya adalah jika Anda menginginkan properti get, set, dan / atau delete-only. Mungkin lebih baik tetap pada properti semantik yang sama dengan nama yang sama.
Kesimpulan
Mulai dengan atribut sederhana.
Jika nanti Anda membutuhkan fungsionalitas di sekitar pengaturan, mendapatkan, dan menghapus, Anda dapat menambahkannya dengan dekorator properti.
Hindari fungsi bernama
set_...
danget_...
- itulah gunanya properti.sumber
__init__
metode ini merujukself.protected_value
tetapi pengambil dan penunjuk mengacu padanyaself._protected_value
. Bisakah Anda jelaskan bagaimana cara kerjanya? Saya menguji kode Anda dan berfungsi sebagaimana mestinya - jadi ini bukan kesalahan ketik.__init__
?self.protected_value = start_protected_value
sebenarnya memanggil fungsi setter; Saya pikir itu adalah tugas.sumber
Menggunakan
@property
dan@attribute.setter
membantu Anda untuk tidak hanya menggunakan cara "pythonic" tetapi juga untuk memeriksa validitas atribut baik saat membuat objek maupun ketika mengubahnya.Dengan ini, Anda sebenarnya 'menyembunyikan'
_name
atribut dari pengembang klien dan juga melakukan pemeriksaan pada tipe properti nama. Perhatikan bahwa dengan mengikuti pendekatan ini bahkan selama inisiasi setter dipanggil. Begitu:Akan mengarah ke:
Tapi:
sumber
Lihat
@property
dekoratornya .sumber
Anda dapat menggunakan accessors / mutators (yaitu
@attr.setter
dan@property
) atau tidak, tetapi yang paling penting adalah konsisten!Jika Anda menggunakan
@property
untuk mengakses atribut, misgunakan untuk mengakses setiap atribut * ! Ini akan menjadi praktik yang buruk untuk mengakses beberapa atribut menggunakan
@property
dan membiarkan beberapa properti lainnya publik (yaitu nama tanpa garis bawah) tanpa pengakses , misalnya jangan lakukanCatatan yang
self.b
tidak memiliki pengakses eksplisit di sini meskipun itu publik.Demikian pula dengan setter (atau mutator ), jangan ragu untuk menggunakan
@attribute.setter
tetapi konsisten! Ketika Anda melakukan misSulit bagi saya untuk menebak niat Anda. Di satu sisi Anda mengatakan bahwa keduanya
a
danb
publik (tidak ada garis bawah terkemuka dalam nama mereka) jadi saya secara teoritis harus diizinkan untuk mengakses / bermutasi (dapatkan / atur) keduanya. Tapi kemudian Anda menentukan mutator eksplisit hanya untuka
, yang memberi tahu saya bahwa mungkin saya seharusnya tidak dapat mengaturb
. Karena Anda telah menyediakan mutator eksplisit, saya tidak yakin apakah kurangnya accessor eksplisit (@property
) berarti saya seharusnya tidak dapat mengakses salah satu dari variabel-variabel tersebut atau Anda cukup hemat dalam menggunakan@property
.* Pengecualiannya adalah ketika Anda secara eksplisit ingin membuat beberapa variabel dapat diakses atau diubah tetapi tidak keduanya atau Anda ingin melakukan beberapa logika tambahan saat mengakses atau bermutasi atribut. Ini adalah ketika saya secara pribadi menggunakan
@property
dan@attribute.setter
(jika tidak tidak ada aksesor / mutator eksplisit untuk atribut publik).Terakhir, saran PEP8 dan Google Style Guide:
PEP8, Merancang untuk Warisan mengatakan:
Di sisi lain, menurut Google Style Guide Aturan / Properti Bahasa Python rekomendasinya adalah untuk:
Kelebihan dari pendekatan ini:
dan kontra:
sumber
@property
, membuat sisanya juga menggunakan@property
sepertinya keputusan yang buruk.@property
(misalnya, mengeksekusi beberapa logika khusus sebelum mengembalikan atribut). Kalau tidak, mengapa Anda mendekorasi satu atribut dengan yang@propery
lain?@property
untuk memulainya, kan? Jika rajin rajinreturn this._x
dan rajin rajinthis._x = new_x
, maka menggunakannya@property
sama sekali konyol.@property
adalah konsisten."Anda dapat menggunakan metode sulap
__getattribute__
dan__setattr__
.Sadarilah itu
__getattr__
dan__getattribute__
tidak sama.__getattr__
hanya dipanggil ketika atribut tidak ditemukan.sumber