亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

物件的描述器

一般來說,一個描述器是一個有「綁定行為」的物件屬性 (object attribute),它的存取控制被描述器協(xié)定方法重寫。這些方法是 __get__(), __set__() , 和 __delete__() 。有這些方法的物件叫做描述器。

預(yù)設(shè)對屬性的存取控制是從物件的字典裡面 (__dict__) 取得 (get) , 設(shè)定 (set) 和刪除 (delete) 。舉例來說, a.x 的查找順序是, a.__dict__['x'] , 然後t(yī)ype(a).__dict__['x'] , 然後找type(a) 的父類( 不包括元類(metaclass) ) .如果查找到的值是一個描述器, Python 就會呼叫描述器的方法來重寫預(yù)設(shè)的控制行為。這個重寫發(fā)生在這個查找環(huán)節(jié)的哪裡取決於定義了哪個描述器方法。注意, 只有在新式類別中時描述器才會起作用。在先前的篇節(jié)中已經(jīng)提到新式類別和舊式類別的,有興趣可以查看之前的篇節(jié)來看看,至於新式類別最大的特點就是所有類別都繼承自 type 或 object 的類別。

在物件導(dǎo)向程式設(shè)計時,如果一個類別的屬性有相互依賴的關(guān)係時,使用描述器來編寫程式碼可以很巧妙的組織邏輯。在 Django 的 ORM 中,models.Model中的 InterField 等字段, 就是透過描述器來實現(xiàn)功能的。

我們先看下面的例子:

#!/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('設(shè)置 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)

輸出的結(jié)果如下:

獲取 name 值
兩點水
設(shè)置 name 值
獲取 name 值
三點水
獲取 name 值
三點水
5

透過這個例子,可以很好的觀察到這__get__() 和_ _set__() 這些方法的呼叫。

再看一個經(jīng)典的例子

我們知道,距離既可以用單位"米"表示,也可以用單位"英尺"表示?,F(xiàn)在我們定義一個類別來表示距離,它有兩個屬性: 公尺和英尺。

#!/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)

輸出的結(jié)果:

0.0 0.0
1.0 3.2808
2.0 6.5616

在上面例子中,在還沒有對Distance 的實例賦值前, 我們認為meter 和foot 應(yīng)該是各自類別的實例物件, 但是輸出卻是數(shù)值。這是因為 __get__ 發(fā)揮了作用.

我們只是修改了 meter ,並且將其賦值成為 int ,但 foot 也修改了。這是 __set__ 發(fā)揮了作用.

描述器物件 (Meter、Foot) 不能獨立存在, 它需要被另一個擁有者類別 (Distance) 所持有。描述器物件可以存取到其擁有者實例的屬性,例如範例中 Foot 的 instance.meter 。

繼續(xù)學(xué)習(xí)