所有的Python 对象都有属性,可以通过 obj.name 这样的语法来获取属性,通过 obj.name = 'Tom' 这样的语法添加一个属性或更新属性的值(如果这个属性已存在),通过 del obj.name
删除一个属性。
特殊属性和自定义属性
根据属性保存位置的不同,可以将属性分类为特殊属性和自定义属性。先来看一个例子。
class Foo:
pass
f = Foo()
print(f.__dict__)
f.name = "Tom"
print(f.__dict__)
print(f.__dict__['name'] is f.name)
print(f.__class__)
f.__dict__['__class__'] = 'My class'
print(f.__class__)
f.__dict__['bar'] = 'xxx'
print(f.bar)
结果为:
{} {'name': 'Tom'} True <class '__main__.Foo'> <class '__main__.Foo'> xxx
从这个例子中,我们可以看出:
- 我们为一个对象新添加的属性都会被保存在 'dict' 这个特殊属性中,'dict'的类型是字典。如在添加了 name 这个属性后, dict 的值变为 {'name': 'Tom'},添加前为一个空字典。
- 对于我们自己新添加的属性,可以通过两种方式来访问这个属性: f.name 和 f.__dict__['name']。这两种方式的效果完全相同,因为它们代表的是同一个变量。因此可认为 f.name 是 f.__dict__['name'] 的一种简写方式。
- 对于任意的属性,f.xyz 的解析过程为:1. 首先检查xyz这个属性在对象中是否存在,如存在,则返回这个属性。2. 否则再检查 xyz这个属性在f.__dict__是否存在,如存在,则返回这个属性。 如上面代码里,尽管我们通过直接在__dict__为对象添加一个名为__class__的属性,但由于这个属性对象本身就定义了,因此它还是原来的值。也即在以上第一步中即找到了这个属性。 而对于'bar' 属性,添加后再查询就是我们添加的值,在以上第2步中找到这个属性。
因此可将一个python对象理解为一个C语言中的结构体,这个结构体的成员在对象创建后,就固定了,无法再添加新的成员。在本文中我们称这些属性为特殊属性。但实际上我们又是可以为一个对象添加新的属性的,这是怎么做到的呢?答案是每个对象都有一个名为__dict__的特殊属性,这个属性的类型为字典,所有新添加的属性都会被保存在这个字典里,在本文中我们称新添加的属性为自定义属性。但python向用户屏蔽两种属性的差别,提供了统一的语法来访问它们,也即通过 obj.name
。这个在大多数情况下会带来便利性,但有时会带来含混,此时我们需要弄清楚到底一个属性是一个特殊属性还是自定义属性。
一些例子
class Foo:
def __init__(self):
self.id = 1
self.name = 'Tom'
def foo(self):
pass
f = Foo()
print(f.__dict__)
print(f.foo)
结果为:
{'id': 1, 'name': 'Tom'} <bound method Foo.foo of <__main__.Foo object at 0x000000B2509ECFD0>>
- 可见一个类的__init__函数对self添加的属性,都将成为这个类实例对象的自定义属性,如例子中的id 和name两个属性。
- 类中定义的函数,将成为类实例的特殊属性,如例子中的foo这个属性,它的类型是method.
对象属性的分类及一些例子
对于任何对象,其属性可分为两种(以下说的都是自己的属性,不包括父类的属性):
- 用户自定义属性。
- 语言定义属性
对于一个class object,其两种属性可能包含:
用户自定义属性 | 语言定义属性 |
---|---|
所有类变量 | mro |
所有类函数 | dict |
所有类描述符 | |
doc | |
module |
那么如何为一个class object添加自定义属性? 在定义一个类时,一个def 语句将添加一个类函数到自定义属性; 一个赋值语句将添加一个类变量到自定义属性。
注:其实对于class object, 它也是type class object 的instance
对于一个instance object, 其两种属性可能包含:
用户自定义属性 | 语言定义属性 |
---|---|
所有属性 | class |
dict |
问题: str.__class__ 是一个语言定义属性还是继承自 其父类 object 的__class__ 用户自定义属性(也即object.__dict__['class'], 这个是一个'attribute')? 应该是一个语言定义属性,应该来自于 object.__dict__['class'], 也可能是
问题二: str.__mro__ 的结果是: (str, object). 但我不知道这个成员来自于何处。 str.__dict__和object.__dict__里都没有。
__dict__属性的作用
__dict__属性是一个语言定义属性,它用来保存所有的用户自定义属性。
属性的查找机制
x.name 等价于 getattr(x, 'name'),