Python 如何查找属性

查看对象内部所有属性名和属性值组成的字典

python 的 dict 属性

类 & 类对象 的 dict 属性

  • 在 Python 类的内部,无论是 类属性 还是 实例属性,都是以字典的形式进行存储的,其中属性名作为键,而值作为该键对应的值。

  • 为了方便用户查看类中包含哪些属性,Python 类提供了 dict 属性。需要注意的一点是,该属性可以用 类名 或者 类的实例对象 来调用。

    • 类名 直接调用 dict,会输出该由类中所有类属性组成的字典
    • 而使用 类的实例对象 调用 dict,会输出由类中所有实例属性组成的字典
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# -*- coding:utf-8 -*-

class CLanguage:
a = 1
b = 2

def __init__ (self):
self.name = "C语言中文网"
self.add = "http://c.biancheng.net"

#通过类名调用__dict__
print(CLanguage.__dict__)

#通过类实例对象调用 __dict__
clangs = CLanguage()
print(clangs.__dict__)
  • 输出
    1
    2
    {'a': 1, '__module__': '__main__', 'b': 2, '__doc__': None, '__init__': <function __init__ at 0x0000000002E22518>}
    {'add': 'http://c.biancheng.net', 'name': 'C\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91'}

类继承

  • 对于具有继承关系的父类和子类来说,父类有自己的 dict,同样子类也有自己的 dict,它不会包含父类的 dict
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# -*- coding:utf-8 -*-

class CLanguage:
a = 1
b = 2
def __init__ (self):
self.name = "C语言中文网"
self.add = "http://c.biancheng.net"

class CL(CLanguage):
c = 1
d = 2
def __init__ (self):
self.na = "Python教程"
self.ad = "http://c.biancheng.net/python"

#父类名调用__dict__
print(CLanguage.__dict__)

#子类名调用__dict__
print(CL.__dict__)

#父类实例对象调用 __dict__
clangs = CLanguage()
print(clangs.__dict__)

#子类实例对象调用 __dict__
cl = CL()
print(cl.__dict__)
  • 结果

    1
    2
    3
    4
    {'a': 1, '__module__': '__main__', 'b': 2, '__doc__': None, '__init__': <function __init__ at 0x0000000003222518>}
    {'__module__': '__main__', '__doc__': None, 'c': 1, '__init__': <function __init__ at 0x0000000003222588>, 'd': 2}
    {'add': 'http://c.biancheng.net', 'name': 'C\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91'}
    {'na': 'Python\xe6\x95\x99\xe7\xa8\x8b', 'ad': 'http://c.biancheng.net/python'}
  • 显然,通过子类直接调用的 dict 中,并没有包含父类中的 a 和 b 类属性;同样,通过子类对象调用的 dict,也没有包含父类对象拥有的 name 和 add 实例属性。

总结

  • class 和 类对象 都有自己的 dict属性
    • 由此可见, 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性- 都是放在类dict里的
    • 类对象的dict中存储了一些self.xxx的一些东西
  • python中的int,list,dict等常用数据类型没有 dict 属性
  • 发生继承时候的 dict 属性
    • 子类有自己的 dict, 父类也有自己的 dict
    • 子类的全局变量和函数放在子类的dict中,父类的放在父类dict中

属性的查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
## -*- coding:utf-8 -*-

class Kls(object):
def __init__(self, a):
super(Kls, self).__init__()

self.a = a

def func(self):
print "self"

def __getattribute__(self, name):
print "in __getattribute__", name
return super(Kls, self).__getattribute__(name)

def __getattr__(self, name):
print "in __getattr__", name


k = Kls(1)
k.a # in __getattribute__, a
k.b # in __getattribute__, b
# in __getattr__, b
k.func # in __getattribute__, func
  • 可以看到,不管属性有没有找到,getattribute 这个方法首先会调用到,这是属性查找的入口。

  • 在这种情况下,属性访问会先去查看k的 dict 。这是一个dict,目前的内容是{“a”: 1},于是查找a属性的时候,直接返回dict里的内容。

  • 而对于b,在k的dict里没找到,python会去a的type,即class的 dict 里去找,Kls这个类的 dict 也没有b,这个时候查找失败,会调用 getattr 这个方法。

  • 值得注意的是,func这个函数是存在类的 dict 里的。这也是为什么reload之后,instance的方法会生效的原因。