Python高級屬性訪問模式

一、關於私有關鍵字

Python中沒有private關鍵字,與之最接近的概念是名稱修飾(name mangling)。每當在一個屬性前面加上雙下劃線_ _時,解釋器就會立即將其重命名,通過這種方式造成對象實例無法直接訪問屬性。

class MyClass:

     __secret_value=1

二、描述符

描述符descriptor允許你自定義在引用一個對象的屬性時應該完成的事情。描述符是python中複雜屬性訪問的基礎。

描述符類基於3個特殊方法,這3個方法組成了描述符協議(descriptor protocol):

1) __set__(self,obj,type=None): 在屬性設置時調用 這一方法。

2)__get__(self,obj,value): 在讀取屬性時調用這一方法。

3)__delete__(self,obj): 對屬性調用del時將調用這一方法。

class RevealAccess(object):
    """
    A data descriptor that sets and returns values
    normally and prints a message logging their access.
    """
    def __init__(self, initval=None, name='var'):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print('Retrieving', self.name)
        return self.val

    def __set__(self, obj, val):
        print('Updating', self.name)
        self.val = val


class MyClass(object):
    x = RevealAccess(10, 'var "x"')
    y = 5


if __name__ == "__main__":
    my_instance = MyClass()

    # set x attribute (will issue print)
    my_instance.x = 4
    # access x attribute (will issue print)
    assert my_instance.x == 4

    # set y attribute (will pass silently)
    my_instance.y = 2
    # access x attribute (will pass silently)
    assert my_instance.y == 2

2.2 property提供了一個內置的描述符類型

class Rectangle:
    def __init__(self, x1, y1, x2, y2):
        self.x1, self.y1 = x1, y1
        self.x2, self.y2 = x2, y2

    @property
    def width(self):
        """rectangle height measured from top"""
        return self.x2 - self.x1

    @width.setter
    def width(self, value):
        self.x2 = self.x1 + value

    @property
    def height(self):
        """rectangle height measured from top"""
        return self.y2 - self.y1

    @height.setter
    def height(self, value):
        self.y2 = self.y1 + value

    def __repr__(self):
        return "{}({}, {}, {}, {})".format(
            self.__class__.__name__,
            self.x1, self.y1, self.x2, self.y2
        )


if __name__ == "__main__":
    rectangle = Rectangle(0, 0, 10, 10)
    print(
        "At start we have {} with size of {} x {}"
        "".format(rectangle, rectangle.width, rectangle.height)
    )

    rectangle.width = 2
    rectangle.height = 8
    print(
        "After resizing we have {} with size of {} x {}"
        "".format(rectangle, rectangle.width, rectangle.height)
    )

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章