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)
    )

 

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