概览
本章的重点就是展示Pythonic,可以理解为python编程的一种风格,比如作者例举的python是用len(collection) 而不是用collection.len()。
Pythonic的关键就是Python data model。作者认为data model可以想象为对python作为一种框架的描述。data model定义了python语言中各个组成部分的接口。
这些接口的定义,就是作者提到的special method(特殊方法)。特殊方法名首尾都是双下划线,例如__getitem__
。python解释器调用特殊方法来完成基础的对象操作。通过在自定义类中实现特殊方法,也可以使让用户的自定义类像python基础对象一样进行操作。
如何实现这些特殊方法,将是后续贯穿全书的内容。
示例
下面展示了一个很Pythonic的例子,看了之后感觉自己之前的python代码太过程语言化了。
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, position):
return self._cards[position]
通过定义了__len__
和__getitem__
就可以像操作list一样操作FrenchDeck类。
>>> deck = FrenchDeck()
>>> len(deck)
52
>>> deck[0]
Card(rank='2', suit='spades')
>>> deck[:3]
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
>>> Card('Q', 'hearts') in deck
True
可以通过这个例子看到,通过实现特殊方法可以带来两个好处:
- 可以让你的类有和标准库一样定义的通用接口
- 可以从python标准库里受益
__repr__和__str__
>>> import datetime
>>> today = datetime.date.today()
>>> str(today)
'2019-01-16'
>>> repr(today)
'datetime.date(2019, 1, 16)'
>>> a = '1'
>>> str(a)
'1'
>>> repr(a)
"'1'"
- 在占位符里repr使用%r,str使用%s
- str返回的结果被用于print方法,侧重于好的格式展示给终端用户
- repr一般是能和重建对象的源代码相匹配
- 当
__str__
没有实现的时候,python将自动调用__repr__