deskriptor objek

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.

Meneruskan pembelajaran
  • Cadangan kursus
  • Muat turun perisian kursus