python cookbook第三版学习笔记十五:property和描述

8.5 私有属性:

在python中,如果想将私有数据封装到类的实例上,有两种方法:1 单下划线。2 双下划线

1 单下划线一般认为是内部实现,但是如果想从外部访问的话也是可以的

2 双下划线是则无法通过外部访问且不能被继承覆盖

来看下面的这个例子:

class B:

    def __init__(self):

        self.__private=0

    def __private_method(self):

        print("__private method")

    def public_method(self):

        self.__private_method()

        print("public method")

 

class C(B):

    def __init__(self):

        super().__init__()

        self.__private=2

    def __private_method(self):

        print("private_method in C")

    def public_method(self):

        self.__private_method()

        print("public method in C")

 

if __name__=="__main__":

    b=B()

    b.public_method()

    c=C()

c.public_method()

运行结果:可以看到在C中虽然也申明了__private_method。但是B类中的函数并没有被C所覆盖

__private method

public method

private_method in C

public method in C

 

8.6 可管理的属性:

要自定义对属性的访问,一种简单的方式就是将其定义为property

class Person():

    def __init__(self,name):

        self.first_name=name

    @property

    def name(self):

        return self.first_name

    @name.setter

    def name(self,name):

        if not isinstance(name,str):

            raise TypeError('Expected a string')

        self.first_name=name

    @name.deleter

    def name(self):

        raise AttributeError('can not delete attribute')

 

通过对name进行property进行修饰,可以将name变成一个属性直接调用。在通过@name.setter就可以对属性进行赋值操作

 

if __name__=="__main__":

    p=Person("abc")

    print(p.name)    

    p.name="zhf"

    print(p.name)

del p.name

 

运行结果:

abc

zhf

Traceback (most recent call last):

  File "D:/py_prj/test2/cookbook.py", line 47, in <module>

    del p.name

  File "D:/py_prj/test2/cookbook.py", line 38, in name

    raise AttributeError('can not delete attribute')

AttributeError: can not delete attribute

 

下面来看一种新式的实例属性。可以用描述符类的形式定义功能。所谓的描述符就是用特殊方法__get__(),__set__(),__del__()。这些方法通过接受类示例作为输入来工作。

class Integer:

    def __init__(self,name):

        self.name=name

    def __get__(self, instance, owner):

        if instance is None:

            return self

        else:

            return instance.__dict__[self.name]

    def __set__(self, instance, value):

        if not isinstance(value,int):

            raise TypeError('expect int')

        instance.__dict__[self.name]=value

    def __delete__(self, instance):

        del instance.__dict__[self.name]

 

class Point():

    x=Integer('x')

    y=Integer('y')

    def __init__(self,x,y):

        self.x=x

        self.y=y

在这里x,y和分别是Integer的实例化对象。但是通过描述符,我们可以把描述符的实例放置在类的定义中作为类变量来使用。当这么做的时候,所有针对描述符属性的访问都会被__get__(),.__set__()和__delete__方法捕获。

 

比如调用self.x的时候其实调用的是Point.x__set__(p,x). 也就是说在Integer的__set__参数instance其实是Point的实例化对象。通过这种描述符的方法,我们就可以对类中的变量自动进行赋值以及类型判断。相比于使用property的方法。这种方法更加简洁

posted @ 2018-08-12 21:04  red_leaf_412  阅读(191)  评论(0编辑  收藏  举报