Saya ingin memahami cara property
kerja fungsi bawaan. Yang membingungkan saya adalah bahwa itu property
juga dapat digunakan sebagai dekorator, tetapi hanya membutuhkan argumen ketika digunakan sebagai fungsi bawaan dan bukan saat digunakan sebagai dekorator.
Contoh ini dari dokumentasi :
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
property
argumen 's adalah getx
, setx
, delx
dan string doc.
Dalam kode di bawah property
ini digunakan sebagai dekorator. Objek itu adalah x
fungsi, tetapi dalam kode di atas tidak ada tempat untuk fungsi objek dalam argumen.
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
Dan, bagaimana dengan x.setter
dan x.deleter
dekorator dibuat? Saya bingung.
property
sebenarnya adalah sebuah kelas (bukan fungsi), meskipun mungkin tidak memanggil__init__()
metode ketika Anda membuat objek, tentu saja. Menggunakanhelp(property)
dari terminal itu berwawasan luas.help
juga kelas karena beberapa alasan.Jawaban:
The
property()
mengembalikan fungsi khusus objek descriptor :Objek inilah yang memiliki metode tambahan :
Ini bertindak sebagai dekorator juga . Mereka mengembalikan objek properti baru:
itu adalah salinan dari objek lama, tetapi dengan salah satu fungsi diganti.
Ingat, bahwa
@decorator
sintaksis hanyalah gula sintaksis; sintaks:benar-benar berarti sama dengan
jadi
foo
fungsinya diganti olehproperty(foo)
, yang kita lihat di atas adalah objek khusus. Kemudian ketika Anda menggunakan@foo.setter()
, apa yang Anda lakukan adalah menyebutnya demikianproperty().setter
metode yang saya tunjukkan di atas, yang mengembalikan salinan properti baru, tetapi kali ini dengan fungsi setter diganti dengan metode yang didekorasi.Urutan berikut juga menciptakan properti penuh, dengan menggunakan metode dekorator tersebut.
Pertama kita membuat beberapa fungsi dan
property
objek hanya dengan pengambil:Selanjutnya kita menggunakan
.setter()
metode untuk menambahkan setter:Terakhir kita tambahkan deleter dengan
.deleter()
metode:Last but not least,
property
objek tersebut bertindak sebagai objek deskriptor , sehingga memiliki.__get__()
,.__set__()
dan.__delete__()
metode untuk menghubungkan ke atribut instance get, setting, dan delete:The Descriptor Howto menyertakan implementasi sampel Python murni dari
property()
tipe:sumber
Foo.prop = prop
Anda bisa lakukanFoo().prop = 5; pront Foo().prop; del Foo().prop
dengan hasil yang diinginkan.type()
mengakses atribut dan metode dunder dimaksudkan untuk digunakan sebagai titik ekstensi oleh fungsi standar dan operator.@human.name.getter
mengubahproperty
objek di tempat alih-alih mengembalikan yang baru,human.name
atribut akan diubah, mengubah perilaku superclass itu.Dokumentasi mengatakan itu hanya jalan pintas untuk membuat properti readonly. Begitu
setara dengan
sumber
@property
sebagai dekorator di kelas mereka.Berikut adalah contoh minimal tentang bagaimana
@property
dapat diterapkan:Kalau tidak,
word
tetap metode bukan properti.sumber
self.word = my_word
- yang kemudian akan bekerja dengan cara yang samaprint( Thing('ok').word ) = 'ok'
Thing('ok').word
memanggil fungsi secara internal saat runtime?Bagian pertama adalah sederhana:
sama dengan
property
hanya dengan pengambil.Langkah selanjutnya adalah memperluas properti ini dengan setter dan deleter. Dan ini terjadi dengan metode yang sesuai:
mengembalikan properti baru yang mewarisi semuanya dari yang lama
x
plus setter yang diberikan.x.deleter
bekerja dengan cara yang sama.sumber
Berikut ini:
Sama dengan:
Sama dengan:
Sama dengan:
Yang sama dengan:
sumber
Di bawah ini adalah contoh lain tentang bagaimana
@property
bisa membantu ketika seseorang harus memperbaiki kode yang diambil dari sini (saya hanya meringkasnya di bawah):Bayangkan Anda membuat kelas
Money
seperti ini:dan seorang pengguna membuat perpustakaan tergantung pada kelas ini di mana ia menggunakan mis
Sekarang anggaplah Anda memutuskan untuk mengubah
Money
kelas Anda dan menyingkirkan atributdollars
dancents
tetapi memutuskan untuk hanya melacak jumlah total sen:Jika pengguna yang disebutkan di atas sekarang mencoba untuk menjalankan perpustakaannya seperti sebelumnya
itu akan menghasilkan kesalahan
Itu berarti bahwa sekarang semua orang yang bergantung pada
Money
kelas asli Anda harus mengubah semua baris kode di manadollars
dancents
digunakan yang bisa sangat menyakitkan ... Jadi, bagaimana ini bisa dihindari? Dengan menggunakan@property
!Begitulah caranya:
ketika kami sekarang menelepon dari perpustakaan kami
ini akan berfungsi seperti yang diharapkan dan kami tidak perlu mengubah satu baris kode pun di perpustakaan kami! Bahkan, kita bahkan tidak perlu tahu bahwa perpustakaan tempat kita bergantung berubah.
Juga
setter
berfungsi dengan baik:Anda dapat menggunakan
@property
juga dalam kelas abstrak; Saya berikan contoh minimal di sini .sumber
self.dollar = dollars
? kami telah melakukan banyak hal dengan @property, tetapi sepertinya tidak ada fungsionalitas ekstrak yang ditambahkan.Saya membaca semua posting di sini dan menyadari bahwa kita mungkin membutuhkan contoh kehidupan nyata. Kenapa, sebenarnya, kita punya @ properti? Jadi, pertimbangkan aplikasi Flask tempat Anda menggunakan sistem otentikasi. Anda mendeklarasikan Pengguna model di
models.py
:Dalam kode ini kita telah atribut "tersembunyi"
password
dengan menggunakan@property
yang memicuAttributeError
pernyataan ketika Anda mencoba mengaksesnya secara langsung, sementara kami menggunakan @ property.setter untuk mengatur variabel instance aktualpassword_hash
.Sekarang
auth/views.py
kita dapat instantiate Pengguna dengan:Atribut pemberitahuan
password
yang berasal dari formulir pendaftaran ketika pengguna mengisi formulir. Konfirmasi kata sandi terjadi di ujung depan denganEqualTo('password', message='Passwords must match')
(jika Anda bertanya-tanya, tapi itu topik yang berbeda terkait bentuk Flask).Semoga contoh ini bermanfaat
sumber
Titik ini telah dibersihkan oleh banyak orang di sana tetapi di sini ada titik langsung yang saya cari. Inilah yang saya rasa penting untuk memulai dengan dekorator @ properti. misalnya:-
Pemanggilan fungsi "get_config ()" akan berfungsi seperti ini.
Jika Anda perhatikan saya belum menggunakan tanda kurung "()" untuk memanggil fungsi. Ini adalah hal dasar yang saya cari pada dekorator @property. Sehingga Anda dapat menggunakan fungsi Anda seperti variabel.
sumber
Mari kita mulai dengan dekorator Python.
Dekorator Python adalah fungsi yang membantu menambahkan beberapa fungsi tambahan ke fungsi yang sudah didefinisikan.
Dalam Python, semuanya adalah objek. Fungsi dalam Python adalah objek kelas satu yang berarti bahwa mereka dapat direferensikan oleh variabel, ditambahkan dalam daftar, diteruskan sebagai argumen ke fungsi lain, dll.
Pertimbangkan potongan kode berikut.
Di sini, kita dapat mengatakan bahwa fungsi dekorator memodifikasi fungsi say_hello kita dan menambahkan beberapa baris kode tambahan di dalamnya.
Sintaksis python untuk dekorator
Mari kita simpulkan semuanya dari pada dengan skenario kasus, tapi sebelum itu mari kita bicara tentang beberapa oop yang berpartisipasi.
Getters dan setter digunakan dalam banyak bahasa pemrograman berorientasi objek untuk memastikan prinsip enkapsulasi data (dipandang sebagai bundling data dengan metode yang beroperasi pada data ini.)
Metode-metode ini tentu saja pengambil untuk mengambil data dan setter untuk mengubah data.
Menurut prinsip ini, atribut kelas dibuat pribadi untuk menyembunyikan dan melindunginya dari kode lain.
Yup, @property pada dasarnya adalah cara pythonic untuk menggunakan getter dan setter.
Python memiliki konsep hebat yang disebut properti yang membuat kehidupan seorang programmer berorientasi objek jauh lebih sederhana.
Mari kita asumsikan bahwa Anda memutuskan untuk membuat kelas yang dapat menyimpan suhu dalam derajat Celcius.
Kode Refactored, Inilah cara kami dapat mencapainya dengan properti.
Dalam Python, properti () adalah fungsi bawaan yang membuat dan mengembalikan objek properti.
Objek properti memiliki tiga metode, pengambil (), setter (), dan hapus ().
Sini,
bisa dipecah sebagai,
Catatan:
Sekarang Anda dapat mengakses nilai suhu dengan menulis.
Kita dapat melanjutkan dan tidak mendefinisikan nama get_temperature dan set_temperature karena mereka tidak perlu dan mencemari namespace kelas.
Cara pythonic untuk mengatasi masalah di atas adalah dengan menggunakan @ properti .
Poin yang Perlu Dicatat -
Seperti yang Anda lihat, kode ini jelas kurang elegan.
Sekarang, mari kita bicara tentang satu scenerio praktis kehidupan nyata.
Katakanlah Anda telah merancang kelas sebagai berikut:
Sekarang, mari kita asumsikan bahwa kelas kita menjadi populer di kalangan klien dan mereka mulai menggunakannya dalam program mereka, mereka melakukan semua jenis tugas pada objek.
Dan Suatu hari yang menentukan, klien tepercaya datang kepada kami dan menyarankan bahwa "x" harus bernilai antara 0 dan 1000, ini benar-benar skenario yang mengerikan!
Karena properti itu mudah: Kami membuat versi properti "x".
Ini bagus, bukan: Anda bisa mulai dengan implementasi paling sederhana yang bisa dibayangkan, dan Anda bebas untuk bermigrasi ke versi properti tanpa harus mengubah antarmuka! Jadi properti bukan hanya pengganti untuk pengambil dan penyetel!
Anda dapat memeriksa Implementasi ini di sini
sumber
property
adalah kelas di belakang@property
dekorator.Anda selalu dapat memeriksa ini:
Saya menulis ulang contoh dari
help(property)
untuk menunjukkan bahwa@property
sintakssecara fungsional identik dengan
property()
sintaks:Tidak ada perbedaan bagaimana kami menggunakan properti seperti yang Anda lihat.
Untuk menjawab pertanyaan
@property
dekorator dilaksanakan melaluiproperty
kelas.Jadi, pertanyaannya adalah untuk menjelaskan
property
kelas sedikit. Garis ini:Adalah inisialisasi. Kami dapat menulis ulang seperti ini:
Arti
fget
,fset
danfdel
:Gambar selanjutnya menunjukkan kembar tiga yang kita miliki, dari kelas
property
:__get__
,,__set__
dan__delete__
ada yang akan ditimpa . Ini adalah implementasi dari pola deskriptor dengan Python.Kita juga bisa menggunakan properti
setter
,getter
dandeleter
metode untuk mengikat fungsi ke properti. Lihat contoh berikut. Metodes2
kelasC
akan mengatur properti menjadi dua kali lipat .sumber
Properti dapat dideklarasikan dalam dua cara.
Anda dapat melihat beberapa contoh yang saya tulis tentang properti dengan python .
sumber
Penjelasan terbaik dapat ditemukan di sini: Dijelaskan Python @Property - Bagaimana Cara Menggunakan dan Kapan? (Contoh Lengkap) oleh Selva Prabhakaran | Diposting pada 5 November 2018
Itu membantu saya memahami MENGAPA tidak hanya BAGAIMANA.
https://www.machinelearningplus.com/python/python-property/
sumber
Ini adalah contoh lain:
Pada dasarnya, sama dengan contoh C (objek) kecuali saya menggunakan x sebagai gantinya ... Saya juga tidak menginisialisasi dalam __init - ... well .. Saya lakukan, tetapi dapat dihapus karena __x didefinisikan sebagai bagian kelas ....
Outputnya adalah:
dan jika saya mengomentari self.x = 1234 di init maka hasilnya adalah:
dan jika saya menetapkan _default = Tidak Ada ke _default = 0 pada fungsi pengambil (karena semua getter harus memiliki nilai default tetapi tidak diteruskan oleh nilai properti dari apa yang saya lihat sehingga Anda dapat mendefinisikannya di sini, dan sebenarnya tidak buruk karena Anda dapat mendefinisikan default satu kali dan menggunakannya di mana-mana) yaitu: def x (self, _default = 0):
Catatan: Logika pengambil ada hanya untuk memiliki nilai dimanipulasi oleh itu untuk memastikan itu dimanipulasi oleh itu - sama untuk pernyataan cetak ...
Catatan: Saya sudah terbiasa dengan Lua dan mampu secara dinamis membuat 10+ pembantu ketika saya memanggil fungsi tunggal dan saya membuat sesuatu yang serupa untuk Python tanpa menggunakan properti dan berfungsi sampai tingkat tertentu, tetapi, meskipun fungsi-fungsi tersebut sedang dibuat sebelumnya sedang digunakan, masih ada masalah dengan mereka dipanggil sebelum dibuat yang aneh karena tidak dikodekan seperti itu ... Saya lebih suka fleksibilitas Lua meta-tables dan fakta saya bisa menggunakan setter / getter aktual bukannya pada dasarnya langsung mengakses variabel ... Saya suka seberapa cepat beberapa hal dapat dibangun dengan Python - misalnya program gui. walaupun yang saya rancang mungkin tidak dapat dilakukan tanpa banyak perpustakaan tambahan - jika saya kode di AutoHotkey saya dapat langsung mengakses panggilan dll yang saya butuhkan, dan hal yang sama dapat dilakukan di Java, C #, C ++,
Catatan: Keluaran kode dalam forum ini rusak - saya harus menambahkan spasi ke bagian pertama kode agar berfungsi - ketika menyalin / menempel memastikan Anda mengonversi semua spasi menjadi tab .... Saya menggunakan tab untuk Python karena di sebuah file yang 10.000 baris ukuran file bisa 512KB hingga 1MB dengan spasi dan 100 hingga 200KB dengan tab yang sama dengan perbedaan besar untuk ukuran file, dan pengurangan waktu pemrosesan ...
Tab juga dapat disesuaikan per pengguna - jadi jika Anda lebih suka lebar 2 spasi, 4, 8 atau apa pun yang dapat Anda lakukan, itu artinya bijaksana bagi pengembang dengan defisit penglihatan mata.
Catatan: Semua fungsi yang didefinisikan di kelas tidak diindentasi dengan benar karena bug dalam perangkat lunak forum - pastikan Anda membukanya jika Anda menyalin / menempel
sumber
Satu komentar: untuk saya, untuk Python 2.x,
@property
tidak berfungsi seperti yang diiklankan ketika saya tidak mewarisi dariobject
:tetapi bekerja ketika:
untuk Python 3, bekerja selalu.
sumber
object
adalah kelas gaya lama, dan kelas gaya lama tidak mendukung protokol deskriptor (yang merupakanproperty
alat untuk bekerja seperti itu). Dalam Python 3, kelas gaya lama tidak ada lagi; semua kelas adalah apa yang kami sebut kelas gaya baru dengan Python 2.