Secara umumnya, deskriptor ialah atribut objek dengan "tingkah laku mengikat", dan kawalan aksesnya ditindih oleh kaedah protokol deskriptor. Kaedah ini ialah __get__(), __set__(), dan __delete__(). Objek dengan kaedah ini dipanggil deskriptor.
Kawalan akses lalai untuk atribut adalah untuk mendapatkan (mendapatkan), menetapkan (menetapkan) dan memadam (memadam) daripada kamus objek (__dict__). Sebagai contoh, susunan carian untuk a.x ialah, a.__dict__['x'], kemudian taip(a).__dict__['x'], dan kemudian cari kelas induk jenis(a) (tidak termasuk metaclass) .Jika nilai yang ditemui ialah deskriptor, Python akan memanggil kaedah deskriptor untuk mengatasi tingkah laku kawalan lalai. Di mana dalam fasa carian berlaku overriding ini bergantung pada kaedah deskriptor yang ditakrifkan. Ambil perhatian bahawa deskriptor hanya berfungsi apabila berada di dalam kelas gaya baharu. Kelas gaya baharu dan kelas gaya lama telah disebut dalam bab sebelumnya Jika anda berminat, anda boleh menyemak bab sebelumnya Ciri terbesar kelas gaya baharu ialah semua kelas mewarisi daripada kelas jenis atau objek.
Dalam pengaturcaraan berorientasikan objek, jika atribut kelas saling bergantung, menggunakan deskriptor untuk menulis kod boleh mengatur logik dengan sangat bijak. Dalam ORM Django, medan seperti InterField dalam models.Model melaksanakan fungsinya melalui deskriptor.
Mari kita lihat contoh berikut terlebih dahulu:
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- class User(object): def __init__(self, name='两点水', sex='男'): self.sex = sex self.name = name def __get__(self, obj, objtype): print('获取 name 值') return self.name def __set__(self, obj, val): print('设置 name 值') self.name = val class MyClass(object): x = User('两点水', '男') y = 5 if __name__ == '__main__': m = MyClass() print(m.x) print('\n') m.x = '三点水' print(m.x) print('\n') print(m.x) print('\n') print(m.y)
Hasil output adalah seperti berikut:
获取 name 值 两点水 设置 name 值 获取 name 值 三点水 获取 name 值 三点水 5
Melalui contoh ini, kita boleh memerhatikan panggilan kaedah ini __get__() dan __set__().
Lihat satu lagi contoh klasik
Kita tahu bahawa jarak boleh dinyatakan dalam unit "meter" atau "kaki". Sekarang kita mentakrifkan kelas untuk mewakili jarak, yang mempunyai dua sifat: meter dan kaki.
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- class Meter(object): def __init__(self, value=0.0): self.value = float(value) def __get__(self, instance, owner): return self.value def __set__(self, instance, value): self.value = float(value) class Foot(object): def __get__(self, instance, owner): return instance.meter * 3.2808 def __set__(self, instance, value): instance.meter = float(value) / 3.2808 class Distance(object): meter = Meter() foot = Foot() if __name__ == '__main__': d = Distance() print(d.meter, d.foot) d.meter = 1 print(d.meter, d.foot) d.meter = 2 print(d.meter, d.foot)
Hasil keluaran:
0.0 0.0 1.0 3.2808 2.0 6.5616
Dalam contoh di atas, sebelum memberikan nilai kepada contoh Jarak, kami berpendapat bahawa meter dan kaki sepatutnya menjadi objek contoh kelas masing-masing, tetapi output ialah nilai berangka. Ini kerana __get__ mula bermain
Kami baru saja mengubah suai meter dan menetapkannya kepada int, tetapi kaki juga diubah suai. Di sinilah __set__ berperanan
Objek deskriptor (Meter, Kaki) tidak boleh wujud secara bebas, ia perlu dipegang oleh kelas pemilik lain (Jarak). Objek deskriptor boleh mengakses sifat contoh pemiliknya, seperti contoh.meter Kaki dalam contoh.
bahagian seterusnya