
Setiap
@property, classmethod, staticmethod Anda, dan bahkan pemanggilan metode biasa di balik layar bekerja pada mekanisme yang sama. Pada deskriptor. Deskriptor adalah kelas apa pun yang mengimplementasikan setidaknya satu metode protokol:
__get__, __set__, atau __delete__. Begitu Anda mengikat instance dari kelas tersebut ke atribut kelas lain, Python mengambil alih kontrol akses.1️⃣ Hierarki Prioritas
Ketika Anda menulis
obj.attr, Python tidak hanya masuk ke kamus. Ia mengikuti rantai yang ketat:▪️ Data Descriptor (mendefinisikan
__set__ atau __delete__). Ia memiliki prioritas absolut. Jika nama atribut dicegat oleh Data-deskriptor, Python mengabaikan instance.__dict__. Inilah mengapa Anda tidak dapat menimpa @property dengan penugasan biasa (jika tidak ada setter).▪️ Kamus instance (
__dict__). Data objek biasa.▪️ Non-Data Descriptor (hanya mendefinisikan
__get__). Metode kelas biasa adalah ini. Mereka berada di dasar prioritas. Jika Anda secara manual menempatkan fungsi dengan nama metode ke dalam __dict__ objek, itu akan menimpa metode asli.2️⃣ Shared State Anti-pattern
Deskriptor diinisialisasi pada tingkat kelas, bukan instance. Ia satu untuk semua. Jika Anda menyimpan data di dalam instance deskriptor, Anda akan menimpa nilai itu untuk semua objek kelas Anda. Jika Vasya mengubah usia, Petya tiba-tiba menjadi tua bersamanya, karena kedua instance mengakses sel memori yang sama dari deskriptor.
Bagaimana cara menulis yang benar?
Simpan status secara ketat di kamus instance itu sendiri. Untuk menghindari penulisan kode yang rumit, di Python 3.6+ diperkenalkan metode ajaib
__set_name__. Ini memungkinkan deskriptor mengetahui nama di mana ia dibuat di kelas, untuk menyimpan data secara legal di __dict__ objek tertentu.class Validator:
def __set_name__(self, owner, name):
# Mengingat nama atribut agar tidak hardcode
self.private_name = f"_{name}"
def __get__(self, instance, owner):
if instance is None:
return self
return getattr(instance, self.private_name)
def __set__(self, instance, value):
# ✅ Menulis data hanya ke kamus INSTANCE TERTENTU
if not isinstance(value, int):
raise TypeError("Hanya integer yang diizinkan")
setattr(instance, self.private_name, value)
class User:
age = Validator() # age_validator.__set_name__ akan mendapatkan name='age'Deskriptor adalah alat enkapsulasi logika yang sangat kuat. Semua keajaiban framework seperti Django atau SQLAlchemy dibangun di atasnya ☝️
#anatomi_python
Komentar
0Belum ada komentar.
Masuk untuk ikut berdiskusi.