动态属性和特性
除特性,Python 还提供丰
富的 API,于控制属性的访问
权限,以及实现动态属性。
使点号访问属性时(如
obj.attr) ,Python 解释会调
特殊的法(如 __getattr__
和__setattr__)计算属性。
户定义的类可以通过
__getattr__ 法实现“虚拟属
性” ,当访问存在的属性时
(如
obj.no_such_attribute) ,即时
计算属性的值。
使动态属性转换数据
使动态属性访问JSON类数据
仅当法使常规的式获取属
性(即在实、类或超类中找
到指定的属性) ,解释才会调
特殊的 __getattr__ 法。
尝试读取存在的属性应该抛出
AttributeError 异常。
处效属性名
对名称为 Python 关键字的属性
做特殊处
keyword.iskeyword
如果 JSON 对象中的键是有效
的 Python 标识符,也会遇到类
似的问题
str 类提供的 s.isidentifier()
法能根据语的语法判断 s 是否
为有效的 Python 标识符。
但是,把效的标识符变成有效
的属性名却容。
解决法,个是抛出异常,
另个是把效的键换成通名
称,如 attr_0、attr_1,等
等。
使__new__法以灵活的式
创建对象
于构建实的是特殊法
__new__:这是个类法(使
特殊式处,因此必使
@classmethod 装饰) ,必须
返回个实。
返回的实会作为第个参数
(即 self)传给 __init__ 法。
__init__其实是初始化法,真正
的构造法是__new__。
我们乎需要编写
__new__ 法,因为从 object
类继承的实现已经够。
__new__ 法也可以返回其他类
的实,此时,解释会调
__init__ 法。
__new__ 法的第个参数是
类,因为创建的对象通常是那个
类的实。
在FrozenJSON.__new__ 法
中,super().__new__(cls) 表达
式会调
object.__new__(FrozenJSON),
object 类构建的实其实是
FrozenJSON 实,即那个实
的 __class__ 属性存储的是
FrozenJSON 类的引。
过,真正的构建操作由解释
调 C 语实现的
object.__new__ 法执。
使shelve模块调整OSCON数
据源的结构
shelve.open 阶函数返回个
shelve.Shelf 实,这是简单的
键值对象数据库,背后由dbm 模
块持,具有下述特点。
shelve.Shelf 是
abc.MutableMapping 的类,
因此提供处映射类型的重要
法。
此外,shelve.Shelf 类还提供
个管 I/O 的法,如 sync
和 close;它也是个上下管
。
只要把新值赋予键,就会保存键
和值。
键必须是字符。
值必须是 pickle 模块能处的对
象。
定要记得关闭 shelve.Shelf 对
象。如果可以,使 with 块确
保 Shelf 对象会关闭。
新实的 __dict__ 属性,把值
设为个映射,能快速地在那个
实中创建堆属性。
使特性获取链接的记录
从数据中创建实属性的名称时
肯定有可能会引缺陷,因为类
属性(如法)可能被遮盖,
或者由于意外覆盖现有的实属
性丢失数据。
使特性验证属性
被装饰的读值法有个 .setter
属性,这个属性也是装饰;这
个装饰把读值法和设值法
绑定在起。
去除重复的法是抽象
抽象特性的定义有两种式:使
特性函数,或者使描述
符类。后者灵活
特性本身就是使描述符类实现
的
特性全解析
虽然内置的 property 经常作
装饰,但它其实是个类。
property 构造法
property(fget=None,
fset=None, fdel=None,
doc=None)
所有参数都是可选的,如果没有
把函数传给某个参数,那么得到
的特性对象就允许执相应的
操作。
在法众多的类定义体中使装
饰的话,眼就能看出哪些是
读值法,哪些是设值法,
按照惯,在法名的前
加上 get 和 set。
特性会覆盖实属性
特性都是类属性,但是特性管
的其实是实属性的存取。
实属性会遮盖类特性
销毁特性对象后就能获取修改的
实属性。
obj.attr 这样的表达式会从 obj
开始寻找 attr,是从 obj.__
class__ 开始,且,仅当类中
没有名为 attr 的特性时,Python
才会在 obj 实中寻找。
这条规则仅适于特性,还适
于整类描述符——覆盖型描
述符(overriding
descriptor) 。
特性其实是覆盖型描述符
特性的档
控制台中的 help() 函数或 IDE
等具需要显示特性的档时,
会从特性的 __doc__ 属性中提取
信息。
为 property 对象设置档字符
的法是传 doc 参数
weight = property(get_weight,
set_weight, doc='weight in
kilograms')
使装饰创建 property 对象
时,读值法(有 @property 装
饰的法)的档字符作为
个整体,变成特性的档。
定义个特性函数
通过特性读取 weight 和 price,
这会遮盖同名实属性。
使 vars 函数审查 nutmeg 实
,查看真正于存储值的实
属性。
在真实的系统中,分散在多个类
中的多个字段可能要做同样的验
证,此时最好把 quantity 函
数放在实具模块中,以重
复使。
最终可能要重构那个简单的
函数,改成扩展的描述符
类,然后使专的类执
同的验证。在第 20 章中,我们
会这么做。
处属性删除操作
定义特性时,可以使
@my_propety.deleter 装饰包
装个法,负责删除特性管
的属性。
在使装饰的经典调法
中,fdel 参数于设置删值函
数。
member =
property(member_getter,
fdel=member_deleter)
还可以实现低层特殊的
__delattr__ 法处删除属性的
操作
处属性的重要属性和函数
影响属性处式的特殊属性
__class__
对象所属类的引(即
obj.__class__ 与 type(obj) 的作
相同) 。
Python 的某些特殊法,如
__getattr__,只在对象的类中寻
找,在实中寻找。
__dict__
个映射,存储对象或类的可写
属性。
有 __dict__ 属性的对象,任何时
候都能随意设置新属性。
如果类有 __slots__ 属性,它的
实可能没有 __dict__ 属性。
__slots__
类可以定义这个这属性,限制实
能有哪些属性。
__slots__ 属性的值是个字符
组成的元组,指明允许有的属
性。
如果 __slots__ 中没有
'__dict__',那么该类的实没有
__dict__ 属性,实只允许有指
定名称的属性。
__slots__ 属性的值虽然可以是
个表,但是最好始终使元
组,因为处完类的定义体之后
再修改 __slots__ 表没有任何
作,所以使可变的序容
让误解。
处属性的内置函数
5 个内置函数对对象的属性做
读、写和内省操作。
dir([object])
出对象的多数属性。
dir 函数的的是交互式使,
因此没有提供完整的属性表,
只出组“重要的”属性名。
dir 函数能审查有或没有
__dict__ 属性的对象。
dir 函数会出 __dict__ 属性
本身,但会出其中的键。
dir 函数也会出类的个特
殊属性,如__mro__、
__bases__ 和 __name__。
如果没有指定可选的 object 参
数,dir 函数会出当前作域
中的名称。
getattr(object, name[, default])
从 object 对象中获取 name 字
符对应的属性。
获取的属性可能来对象所属的
类或超类。
如果没有指定的属性,getattr 函
数抛出 AttributeError 异常,或
者返回 default 参数的值(如果
设定这个参数的话) 。
hasattr(object, name)
如果 object 对象中存在指定的
属性,或者能以某种式(如
继承)通过 object 对 象 获 取
指 定 的 属 性, 返 回 True。
这个函数的实现法是调
getattr(object, name) 函数,看
看是否抛出 AttributeError 异
常。
setattr(object, name, value)
把 object 对象指定属性的值设
为 value,前提是 object 对象能
接受那个值。
这个函数可能会创建个新属
性,或者覆盖现有的属性。
vars([object])
返回 object 对象的 __dict__ 属
性;如果实所属的类定义
__slots__ 属性,实没有
__dict__ 属性,那么 vars 函数
能处那个实(相反,dir
函数能处这样的实) 。
如果没有指定参数,那么 vars()
函数的作与 locals() 函数
样:返回表示本地作域的字
典。
处属性的特殊法
在户定义的类中,下述特
殊法于获取、设置、删除和
出属性。
使点号或内置的 getattr、
hasattr 和 setattr 函数存取属性
都会触发下述表中相应的特殊
法。
但是,直接通过实的 __dict__
属性读写属性会触发这些特殊
法——如果需要,通常会使
这种式跳过特殊法。
要假定特殊法从类上获取,即
操作标是实也是如此。因
此,特殊法会被同名实属
性遮盖。
__delattr__(self, name)
只要使 del 语删除属性,就
会调这个法。
如,del obj.attr 语触发
Class.__delattr__(obj, 'attr')
法。
__dir__(self)
把对象传给 dir 函数时调,
出属性。
如,dir(obj) 触发
Class.__dir__(obj) 法。
__getattr__(self, name)
仅当获取指定的属性失败,搜索
过 obj、Class 和超类之后调
。
表达式 obj.no_such_ attr、
getattr(obj, 'no_such_attr') 和
hasattr(obj, 'no_such_attr') 可
能 会 触 发
Class.__getattr__(obj,
'no_such_attr') 法,但是,仅
当在 obj、Class 和超类中找
到指定的属性时才会触发。
__getattribute__(self, name)
尝试获取指定的属性时总会调
这个法,过,寻找的属性是
特殊属性或特殊法时除外。
点号与 getattr 和 hasattr 内置
函数会触发这个法。
调__getattribute__法且抛出
AttributeError 异常时,才会调
__getattr__ 法。
为在获取 obj 实的属性时
导致限递归,__getattribute__
法的实现要使 super().__
getattribute__(obj, name)。
__setattr__(self, name, value)
尝试设置指定的属性时总会调
这个法。
点号和 setattr 内置函数会触发
这个法。
如,obj.attr = 42 和
setattr(obj, 'attr', 42) 都会触发
Class.__setattr__(obj, ‘attr’,
42) 法。
与定义这些特殊法相,使
特性或描述符相对出错。
评论0