首先来了解一个概念--协议。在Python
构建功能完善的序列没有必要使用继承,只需要实现序列所需要的协议即可。
而所谓的协议是指非正式的接口集合。比如,spam类只要实现了__len__
和__getitem__
两个方法,不管是谁的子类,它都会表现得像序列一样。
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]
虽然FrechDeck
没有继承任何序列,但它本身已经是序列了,因为它的行为和序列一样,这就叫做鸭子类型。
下面实现一个支持切片操作的序列:
class Vector:
# 省略了很多行
# ...
def __len__(self):
return len(self._components)
def __getitem__(self, index):
cls = type(self)
if isinstance(index, slice):
return cls(self._components[index])
elif isinstance(index, numbers.Integral):
return self._components[index]
else:
msg = '{cls.__name__} indices must be integers'
raise TypeError(msg.format(cls=cls))
>>> v7 = Vector(range(7))
>>> v7[-1]
6.0
>>> v7[1:4]
Vector([1.0, 2.0, 3.0])
>>> v7[-1:]
Vector([6.0])
>>> v7[1,2]
Traceback (most recent call last):
...
TypeError: Vector indices must be integers
接下来我们添加代码,使vector类支持哈希操作:
from array import array
import reprlib
import math
import functools
import operator
class Vector:
typecode = 'd'
# 排版需要,省略了很多行...
def __eq__(self, other):
return tuple(self) == tuple(other)
def __hash__(self):
hashes = map(hash, self._components)
return functools.reduce(operator.xor, hashes, 0)
def __eq__(self, other):
return len(self) == len(other) and all(a == b for a, b in zip(self,other))
网友评论