[toc]

Python的模型

一摞Python风格的纸牌

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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]
  • namedtuple方法用于构建一些只有属性但没有方法的简单类(比如数据库条目)
  • __len__和__getitem__是Python的两个特殊方法,分别对应了len(obj)和obj[],现在对这两个方法进行了重写,FrenchDeck类的对象再调用这两个特殊方法时就会走重写的逻辑
  • 由于__getitem__将[]指向了self._cards,FrenchDeck对象将支持所有[]的功能比如切片、获取首尾元素,==这里没看懂实用性在哪毕竟self._cards本身也是一个list也有这些功能==

如何使用特殊方法

上面提到的__len__和__getitem__是Python的特殊方法,这些特殊方法是给Python调节器用的,开发者不要直接去调用,而是通过len()

  • 当对自定义的类使用len()方法时会去调用自定义实现的__len__;当对内置类型使用len(),那么 CPython 会抄个近路,len 实际上会直接返回 PyVarObject 里的 ob_size 属性。PyVarObject是表示内存中长度可变的内置对象的 C 语言结构体。直接读取这个值比调用一个方法要快很多
  • 通常代码无需直接调用特殊方法,特例是__init__
  • 通过内置函数(len、str、iter)来使用特殊方法,内置函数会有额外的优化,性能更高,后续会详细的说明
  • 最好不要自行定义特殊方法,比如__foo__,当前版本该方法没有被使用,但在后续的版本中就不一定了

模拟数值类型

通过重写__add__、__mul__等特殊方法来实现一个二维向量类,直接实现+、*等操作

字符串表示形式

通过__repr__方法的重新,可以实现类似java中toString方法的效果

特殊方法一览

Python中共计有83个特殊方法,其中47个用于实现算术运算,这里不一个个全列出来了

len为什么不是一个普通方法

实用大于纯粹,之前也提到了,内置的对象实用len时能够获得更高的性能,Python也提供给了自义定类使用len的方法,在语言一致性上找到了平衡点(==这里不太理解如果把len作为一个普通方法让内置类去实现为什么就不能走性能捷径了,应该是语言结构决定的后续应该会讲==)