所有的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.

对象属性的分类及一些例子

对于任何对象,其属性可分为两种(以下说的都是自己的属性,不包括父类的属性):

  1. 用户自定义属性。
  2. 语言定义属性

对于一个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'),