1. 特殊方法示例:一摞Python风格的纸牌
import collections
Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck: # Python2中要写成FrenchDeck(object)
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] # Python 会忽略代码里 []、 {} 和 () 中的换行
def __len__(self):
return len(self._cards)
def __getitem__(self, position):
return self._cards[position]
仅仅实现了__getitem__
方法,这一摞牌就变成可迭代的了,并且支持切片操作
实现spades_high
函数,就可以对这摞牌进行升序排序了:
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
def spades_high(card):
rank_value = FrenchDeck.ranks.index(card.rank)
return rank_value * len(suit_values) + suit_values[card.suit]
for card in sorted(deck, key=spades_high):
print(card)
2. 更多特殊方法
from math import hypot
class Vector:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __repr__(self):
return 'Vector(%r, %r)' % (self.x, self.y)
def __abs__(self):
return hypot(self.x, self.y)
def __bool__(self):
return bool(abs(self))
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y
return Vector(x, y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
实现__abs__
, __bool__
, __add__
, __mul__
方法就能对Vector
对象进行对应的操作
-
__repr__方法
-
在
__repr__
的实现中,我们用到了%r
来获取对象各个属性的标准字符串表示形式——这是个好习惯,它暗示了一个关键:Vector(1, 2)
和Vector('1', '2')
是不一样的,后者在我们的定义中会报错,因为向量对象的构造函数只接受数值,不接受字符串 -
__repr__
和__str__
的区别在于,后者是在str()
函数被使用,或是在用print
函数打印一个对象的时候才被调用的。如果一个对象没有__str__
函数,解释器会用__repr__
代替
-
-
__bool__方法
- 默认情况下,我们自己定义的类的实例总被认为是真的。如果类不存在
__bool__
方法,那么bool(x)
会尝试调用x.__len__()
。若返回 0,则 bool 会返回 False;否则返回 True。
- 默认情况下,我们自己定义的类的实例总被认为是真的。如果类不存在