文章目录
- Fluent Python
- Python Data Model
- A Pythonic Card Deck
- Python Special Method
- Python Jargon
Fluent Python
自己用Python这门语言有一段时间了,但总觉得对它的理解不够透彻,就去相关社区问了一下有什么书籍推荐可以提升自己对Python的理解,挺多人都推荐看一下《Fluent Python》这本书的。看了以后觉得非常惊讶,原来Python这门语言的设计可以如此的优雅,对自己的编程帮助相当大,于是想写一个系列来记录自己看书期间都有学到了什么。
首先说一下可以从哪里获取到这本书的电子版,推荐一个免费电子书下载网站,here,基本可以涵盖你需要的所有电子书,我自己现在一般是在这个网站上下载技术书籍,它真的还没让我失望过:)。
首先说一下读了这本书有哪些好处:
- 可以让你码出Pythonic的代码:Pythonic的意思就是你的代码符合社区规范,容易让人理解,避免重复造轮子。
- 可以了解到很多关于Python的一些鲜为人知却又很有帮助的工具:比如Python提供的并行工具包ftures.ProcessPoolExecutor,我现在的研究工作里真的会经常用到。
- 可以了解到很多关于Python社区的行话:这些行话让人很有“逼格”,比如dunder methods,duck typing等等。
- 可以了解更多如何学习Python的资源:自己最喜欢这本书的一点是,毕竟这本书比较紧凑,不能涵盖有些知识的方方面面,所以作者在每个章节后面都提供了further reading,要么是一些博客,或者Python的官方文档,或者是一些书籍推荐。如果你想进一步探究相关的技术,这些扩展阅读相当有帮助。举个例子,你能说一下“What makes Python so awesome?",一位Python核心开发者Raymond Hettinger分享了它自己的观点,here(视频在YouTube上,但我觉得这对程序员来说不是问题,嘿嘿)。
另外,这本书籍不太适合用来入门Python这门语言,如果想入门的话非常建议去看一下Python的官方教程。说一下自己关于入门Python的一些意见,可以先看一两篇博客,像那些10分钟入门系列,然后,其实你就可以说入门了。。或者你如果喜欢视频教学的方式,从Youtube上找一些入门教程(最好在30分钟左右的那种),看一遍,自己对着敲一下,就可以了。特别是有编程经验的小朋友,完全没有必要从什么运算符啊,ifelse,循环啊之类的学起,因为语言之间都是相同的,你真正要做的是动起来,多用就是了。
下面是真正的干货了
Python Data Model
书的第一章节给我们简单地介绍了什么是Python的数据模型。可以简单地理解为Python这门语言给我们提供的一个框架。我们知道在使用框架的时候,很多我们实现的方法在运行期间都是由框架调用的,这样可以省去很多的工作。Python的数据模型也一样,它提供了一套完整的接口,如果你的代码完美地实现了这些接口,那么就能很好地利用Python语言提供的强大功能。举个栗子,用Python实现一副纸牌。
A Pythonic Card Deck
我们会发现,只是简简单单地实现两个特殊方法__getitem__
和 __len__
,我们的纸牌就可以具备非常强大的功能:
import collections
Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, index):
return self._cards[index]
首先说一下collections.namedtuple
,这个方法用来创建一个简单的卡片类Card
,这个卡片类只有属性rank
和suit
,而没有用户自定义的方法,所以它的功能就只是用来存储数据的。我们先创建纸牌的一个实例:
>>> deck = FrenchDesk()
然后来看一下纸牌都支持哪些操作。
- 查看卡片数目
>>> len(deck)
52
- 下标索引操作
>>> deck[0]
Card(rank='2', suit='spades')
>>> deck[-1]
Card(rank='A', suit='hearts')
- 从纸牌中随机抽取一张牌(结果可能跟自己电脑上的不一样)
>>> from random import choice
>>> choice(deck)
Card(rank='3', suit='hearts')
>>> choice(deck)
Card(rank='K', suit='spades')
>>> choice(deck)
Card(rank='2', suit='clubs')
- 循环访问整副纸牌的每张牌
>>> for card in deck:
... print(card)
Card(rank='2', suit='spades')
Card(rank='3', suit='spades')
Card(rank='4', suit='spades')
...
- 甚至可以逆序访问每张牌
>>> for card in reversed(deck):
... print(card)
Card(rank='A', suit='hearts')
Card(rank='K', suit='hearts')
Card(rank='Q', suit='hearts')
...
- 还可以查看某张牌在不在这幅纸牌里面
>>> Card('7', 'hearts') in deck
True
>>> Card('0', 'hearts') in deck
False
另外,你还可以对纸牌进行排序,具体怎么做可以去看看书。
Python Special Method
上面纸牌的例子里我们提到了Python的两个特殊方法__len__
和__getitem__
,当然__init__
也是。这些特殊方法的命名都有一个特点,就是他们都以两个下滑线_
字符开始和结束。前面说了,Python的数据模型就可以理解为一套框架,这些框架提供特殊方法作为接口,你的程序只要重写这些特殊方法,那么就已经实现了相应的功能。比如__len__
方法,你在里面定义纸牌的数目,然后外面调用len(deck)
,Python编译器内部就会调用相应的特殊方法,即__len__
去实现指定的功能。类似地,使用下标索引的时候会触发__getitem__
方法的调用。关于特殊方法要注意的地方:
- 自己程序的变量命名一般不要以两个下划线开始和结束,因为这种方式一般是用来命名特殊方法的,虽然现在可能还没有被占用,但难保后面的Python版本会使用到这样的名字;
- 特殊方法是Python编译器调用的,我们的代码里一般使用相应的库函数,比如
len, iter, vars
,而不是直接调用my_obj.__len__()
; - 实现这些特殊方法可以让你的代码更加Pythonic,也可以避免重复造轮子。
Python Jargon
- Pythonic:编写的Python代码符合社区规范的,容易广泛流传,而且也是编译器友好的
- dunder method:在称呼特殊方法的时候,叫”under under x“很麻烦,而且
__x
是有特殊含义的,叫"under under x under under"就更加累赘了,所以别人一般会称某个特殊方法为"dunder x",dunder表示"double under"的意思。