先写个算是开篇语的东西吧。从去年起就开始关注rustpython这个项目,也一直想写一系列长篇文章来深入分析这个项目。这样一直拖了差不多一年了,总想着先把整个项目看完再书写一套有体系有章法的文章,但事实证明碎片的时间还是不足以让我把整个项目看完。因此,在今天决定,不管什么体系了,就按照随笔来写吧,看到啥写啥。正好之前因为追求高质量的文章,这个博客之前几个月才更新一次,所以这也算是一个尝试,当然,龟速更新的文章我也会继续写的。如果你看到这系列文章感觉还有点意思,可以把我的网站加收藏哈~ http://blog.ideawand.com 。我还有一个微信公众号叫做【极客幼稚园】,大家也可以关注一下,这样有什么更新大家也可以看到。
本系列随笔的第一篇,基本算是随机挑选的,我们来看看个python中__getattribute__
这个魔术方法在rustpython中有关的实现吧。
本次阅读对应的rustpython commit: 1976740d3c0015514db8863584ed7a015c18521f。
PyAttributes
类型的定义在RP中是用的Rust标准库的HashMap,代码注释中(pyobject.rs:64)的说明是这样可能会比用dict更快一些。而CPython里毕竟C语言自己没有hashmap,所以用的都是CPython自己实现的dict来做。
- 但是毕竟逃不掉,还要和Python语言中的字典有些关系,所以在RustPython的
Dict
实现中,实现了与PyAttributes
的互相转换(from_attributes
@ dict.rs:377、to_attributes
@ dict.rs:452)。
为PyType
实现SlotGetattro
Trait,定义了getattro
方法,流程如下:
PyType
为解释器自己快速查找一个类型的属性开了后门,定义了get_attr
方法。先调用这个方法- 该方法先尝试直接从自己的
attributes
属性(上面提到了,他没有有dict实现,而是直接使用了HashMap)里去按名字查找- 如果没有找到,再去自己的MRO里面找,也是遍历MRO,直接读它们的
attributes
属性
- 如果没有找到,再去自己的MRO里面找,也是遍历MRO,直接读它们的
- 该方法先尝试直接从自己的
Python官方的《Descriptor HowTo Guide》中有如下的描述
1 | Instance lookup scans through a chain of namespaces giving data descriptors the highest priority, followed by instance variables, then non-data descriptors, then class variables, and lastly __getattr__() if it is provided. |
我暂时认为可以这样理解,Python默认为object
、type
、super()
三种类型实现了默认的__getattribute__
方法,默认方法里支持了描述器的行为。我们大多数自定义的结构都继承了这些行为,当然,你也可以自定义一个__getattribute__
方法,这样描述器的机制在当前类就不一定有效了。不过由于在编写自定义的__getattribute__
方法时,为了避免无限递归调用,不能使用self.xxx
的语法,而是显示使用父类的__getattribute__
方法,因此描述器的机制在父类中还会起作用。
__set__
只在当前类下找,而__get__
要按MRO顺序找,为什么呢,存疑,再看看文档
上文提到对于object
、type
、super()
三种类型实现了默认的__getattribute__
方法,所以在RP的代码中也可以在不同位置看到这些逻辑
generic_getattribute_opt
@ vm.rs:1244 这个对应实现了CPython中的_PyObject_GenericGetAttrWithDict
getattro
@ pytype.rs:539- 目前的感觉是,vm.rs中的逻辑是对普通对象的,而pytype.rs中的逻辑是对type的,对super的应该是通过某种方式最终使用了上面两个方法
未完待续。。。。
参考资料: