《Fluent Python》1:Python对象模型
前言
Python的一致性(consistency)是很好的,这意味着如果你可以依据所熟悉的特性来类比新特性。
对象模型(Data Model)是构建Python大厦的框架,指包括了sequences,iterators,函数,类等在内的Python组织方式和操作方式。当你在实现自己的对象时,熟悉对象模型可以帮你简化开发,提升效率。
Pythonic?
通常在一个语言后面加ic
表示符合这种语言的习惯的做法,可以理解为入乡随俗——如果你不这么做,不一定是错的,但是会让熟悉这门语言的人感到不舒服。比如我们说英式英语,在口音纯正的英国人听来就觉得很奇怪,发音不标准,正如很多歪果仁说中文一样,虽然没错,但总感觉音调之类不对劲。那么Pythonic就好像是你说Python这门语言所应该知道的一些惯例。(暂时没想到更好的表述)
Python的类通常有一些特殊方法,以双下划线开头结尾,它们由某些操作符触发,由语言本身隐式调用,可以类比C++的重载,比如a[x]
会触发a.__getitem__()
方法,当然也可以显式调用,不过为什么不用更方便和优雅的隐式调用呢?再比如a+b
会调用a.__add__()
等,这些就是所谓Pythonic的一部分。
例子:一个卡牌类
|
|
正如上文所说,接下来我们就可以用下标来访问FrenchDeck
类的成员,而不需要自己想一个名字,对使用者造成不必要的困扰(我应该用size()
还是length()
去获取它的长度呢?)
|
|
更大的优势在于,一旦你遵循Python对象模型标准去设计你的类,就可以享受标准库提供的基于这些API的强大的众多API,比如只要实现了__getitem__()
,就可以直接享受random.choise
的红利而不需要自己实现。
|
|
另外,实现了__len()__
和_getitem__()
,FrenchDeck就是可迭代的了,意味着我们可以在for中使用它,以及reserved(deck)
(反序循环),sorted(deck)
(不过需要自己提供一个排序函数)。
__方法__如何被调用
正如前文所说,特殊方法是由Python解释器负责调用的,并不需要你手动调用。
|
|
重点讲几个方法,第一个__rper__()
,这个是在交互式终端和调试器中,Python用来展示你的类的对象的方式,比如下面就会输出v1+v2的表示。
|
|
类似地,__str__()
方法是当这个类的对象被用于构造字符串类型时用的,另外会隐式地被print函数所调用,注意这两个函数还是有区别的。
__bool__()
方法。默认地,用户自定义类的对象为true,但如果实现了__len__()
,__bool__()
方法,解释器就会通过这些方法去判断。优先级是__bool__()
> __len__()
。当你显示地调用bool(x)
时,解释器会隐式调用__bool__()
方法。
特殊方法总结
分两类,操作符和非操作符类的。
另,一个细节是当你调用len(x)
,其实并不会invoke*(这个单词经常用,感觉挺正宗的,意思是调用、触发)*__len__()
方法,这是出于效率的考虑。Python之禅讲到:Practically beats puricy,len方法为了效率,在CPython的实现中是直接从表示当前对象的结构体中读取的,为了实用性牺牲了纯粹性。