Python类与对象学习心得-8:处理属性的重要属性和函数

1. 影响属性处理方式的 3 种特殊属性

__class__

对象所属类的引用(即 obj.__class__,与 type(obj) 的作用相同)。Python 的某些特殊方法,例如 __getattr__,只在对象的类中寻找,而不在对象实例中寻找。

__dict__

一个字典(映射),存储对象或类的可写属性。有 __dict__ 属性的对象,任何时候都能随意设置新属性。如果类有 __slots__ 属性,它的实例可能没有 __dict__ 属性。参见下面对 __slots__ 属性的说明。

__slots__

类可以定义这个这属性,限制实例能有哪些属性。__slots__ 属性的值是一个字符串组成的元组,指明实例允许有的属性。 如果 __slots__ 中没有 '__dict__',那么该类的实例没有 __dict__ 属性,实例只允许有指定名称的属性。

2. 处理属性的 5 个内置函数

dir([object])

列出对象的大多数属性名。官方文档(https://docs.python.org/3/library/functions.html#dir)说,dir 函数的目的是交互式使用,
因此没有提供完整的属性列表,只列出一组“重要的”属性名。dir 函数能审查有或没有 __dict__ 属性的对象。dir 函数不会列出 __dict__ 属性本身,但会列出其中的键。dir 函数也不会列出类的几个特殊属性,例如 __mro__、__bases__ 和 __name__。
如果没有指定可选的 object 参数,dir 函数会列出当前作用域中定义的所有名称。

getattr(object, name[, default])

从 object 对象中获取 name 字符串(作为 key)对应的属性值(value)。获取的属性可能来自对象所属的类或所有父类。如果对象没有这个指定的属性,getattr 函数抛出 AttributeError 异常,或者返回 default 参数的值(如果设定了这个参数的话)。

hasattr(object, name)

如果 object 对象中存在指定的属性,或者能以某种方式(例如继承)通过 object 对象获取指定的属性,返回 True。文档
(https://docs.python.org/3/library/functions.html#hasattr)说道:“这个函数的实现方法是调用 getattr(object, name) 函数,看看是否抛出 AttributeError 异常。”

setattr(object, name, value)

把 object 对象指定属性(name)的值设为 value,前提是 object 对象能接受那个值。这个函数可能会创建一个新属性,或者覆盖现有的属性

vars([object])

返回 object 对象的 __dict__ 属性(字典);如果实例所属的类定义了 __slots__ 属性,实例没有 __dict__ 属性,那么 vars 函数不能处理那个实例(相反,dir 函数能处理这样的实例)。如果没有指定参数,那么 vars() 函数的作用与 locals() 函数一样:返回
表示本地作用域的字典。

3. 处理属性的特殊方法

在用户自己定义的类中,下述特殊方法用于获取、设置、删除和列出属性。使用点号或内置的 getattr、hasattr 和 setattr 函数存取属性都会触发下述列表中相应的特殊方法。但是,直接通过实例的 __dict__ 属性读写属性不会触发这些特殊方法——如果需要,通常会使用这种方式跳过特殊方法。

Python 文档“Data model”一章中的“3.3.9. Special method lookup”(https://docs.python.org/3/reference/datamodel.html#special-method-lookup)警告说:对用户自己定义的类来说,如果隐式调用特殊方法,仅当特殊方法在对象所属的类上定义,而不是在对象的实例字典中定义时,才能确保调用成功。也就是说,要假定特殊方法从类上获取,即便操作目标是实例也是如此。因此,特殊方法不会被同名实例属性遮盖。

在下述示例中,假设有个名为 Class 的类,obj 是 Class 类的实例,attr 是 obj 的属性

不管是使用点号存取属性,还是使用上一节列出的某个内置函数,都会触发下述特殊方法中的一个。例如,obj.attr 和 getattr(obj, 'attr', 42) 都会触发 Class.__getattribute__(obj, 'attr') 方法。

__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) 方法。

其实,特殊方法 __getattribute__ 和 __setattr__ 不管怎样都会被触发,几乎会影响每一次属性存取,因此比 __getattr__ 方法(只处理不存在的属性名)更难以正确使用。与定义这些特殊方法相比,使用特性(property)描述符(descriptor)相对不易出错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值