自省是通过一定的机制查询到对象的内部结构 ,Python中提供了很多的方法来查询对象的内部结构,比如: hasattr:查询对象是否有一个特性的属性 ;getattr:获取对象的属性 ;setattr:设置对象的属性 ;delattr:从一个对象中删除属性,这些都是比较常规的方法,我们今天主要来讲一下__dict__dir()这两个方法,我们先来看一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 自省是通过一定的机制查询到对象的内部结构
class Person:
name = "user"


class Student(Person):
def __init__(self, school_name):
self.school_name = school_name


if __name__ == '__main__':
user = Student("家里蹲大学")

# 通过__dict__来查询属性
print(user.__dict__)
print(user.name)

# 输出结果:
{'school_name': '家里蹲大学'}
user

看到这里你可能就会想,为什么这个name属性没有进入我们这个dict里面去呢?那是因为这个name是我们Person这个对象的属性,并不是实例化对象的,之所以打印user.name会出现这个属性,是因为我们在前面说过mro,对象本身不具有就会向上查找,看它的类是不是具有(name属性不属于实例化的对象,只是你可以调用而已)

既然如此,我们来看看Person这个对象,看它具有什么属性(输出一个字典):

1
2
3
4
print(Person.__dict__)

# 输出结果:
{'__module__': '__main__', 'name': 'user', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}

看到没有,里面就有name这个属性了,要知道类是比对象丰富的多,所以具有的属性多也很正常,但在这里我们最关心的还是这个name属性的归属问题。

我们再来看看这个,我们发现我们是可以直接对其属性进行操作的:

1
2
3
4
5
user.__dict__["address"] = "上海市"
print(user.address)

# 输出结果:
上海市

现在我们试试另一个函数dir(),它可以列出所有对象名的属性,比前面的__dict__魔法函数的功能更加强大,不过只会列出属性名,而不会列出属性的值(一个列表):

1
2
3
4
5
print(dir(user))

# 输出结果:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'address', 'name', 'school_name']

也就是说Python的对象其实就是在我们基本的数据结构dict上面进行了一些更高层次的封装,所以我们可以通过对dict的操作从而达到操作对象的目的。