Python属性查找过程分析

国际惯例,来看一段入门级代码。

class Student(object):
    address = '北京'

    def __init__(self):
        self.age = 18


stu = Student()
print(stu.age)
print(stu.address)

相信输出大家都猜到了,结果为:18 北京
那么,有没有想过,是怎么查找到对应的属性的,为什么执行一个不存在的属性程序就会挂掉呢?下面,简单来一步步分析下。

dir查看对象和类信息

通过dir来看一下对象和类都包含了哪些信息。

print(dir(stu))
print(dir(Student))

输出结果为:

['__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', 'age']

['__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']

可以发现,两者都包括一个dict的东东,并且对象的实例变量和类变量都会存在于dir()方法中。下面看一下两者的dict又包含了什么东东呢?

dict查看键值对信息

代码如下:

print(stu.__dict__)
print(Student.__dict__)

输出结果为:

{'age': 18}

{'__module__': '__main__', 'address': '北京', '__init__': <function Student.__init__ at 0x102261620>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}

有木有发现,不管是定义的类变量也好,实例变量也好,都在dict这个魔术方法中以key:value的形式进行保存。

分布结论

通过上面两步呢,可以得到一个结论,在调用对象的变量时,先在对象的dict这个魔术方法进行查找,查找到返回,如果找不到继续在类的dict中进行查找。

进一步分析

在如上程序中,如果我们执行stu.name,那么程序就挂掉了,因为没在两个dict中查到对应的信息,下面,通过复写一个方法,就可以屏蔽掉报错信息了。

    def __getattr__(self, item):
        return 'not found'

getattr这个方法,就是在我们从两个dict查找失败时,会进行调用的方法,加了上述代码后,在执行stu.name就会输出not found信息了。

getattr和getattribute区别

不知道聪明的你有木有发现,除了上面说的getattr方法外,还有一个getattribute方法,那么两者有什么区别么,废话不说,直接上代码。

    def __getattr__(self, item):
        return 'not found'

    def __getattribute__(self, item):
        return 'getattribute called'

下面,再运行我们的程序,输出结果为:

getattribute called
getattribute called

这是为什么呢?
不难发现,复写这个方法后,都没从dict中进行数据查找,而是直接打印这个方法信息了。

大结论

在调用对象方法时,先调用getattribute方法,从这个方法中进行数据查找分发,先到对象的dict,如果查找失败,接着到类的dict,如果还失败,就会到getattr方法中,一般而言,可以在getattr方法中进行自己的一些操作,而很少去改动getattribute方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值