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

时间:2023-03-10 00:56:16
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的方法。这种方法更加简洁