魔术方法(magic method)是特殊方法的昵称,“双下- getitem”(dunder-getitem)这种说法。于是乎,特殊方法也叫双下方法(dunder method)。
一摞Python风格的纸牌
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import collections from random import choice
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]
beer_card = Card('7','diamonds') print(beer_card)
deck = FrenchDeck() print(len(deck))
print(deck[0])
print(choice(deck))
for card in deck: print(card)
|
如何使用特殊方法
特殊方法的存在是为了被Python解释器调用的,你自己并不需要调用它们。也就是说没有my_object.__len__()
这种写法,而应该使用len(my_object)
。
特殊方法的调用是隐式的,比如for i in x:
这个语句,背后其实用的是iter(x)
,而这个函数的背后则是x.__iter__()
方法。
模拟数值类型
一个简单的二维向量类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| 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)
v = Vector(2, 3) v1 = Vector(6, 8)
print(abs(v1*3)) print(repr(v1)) print(v+v1*2)
|
字符串表示形式
__repr__
和__str__
的区别在于,后者是在str()
函数被使用,或是在用print
函数打印一个对象的时候才被调用的,并且它返回的字符串对终端用户更友好。
如果你只想实现这两个特殊方法中的一个,__repr__
是更好的选择,因为如果一个对象没有__str__
函数,而Python又需要调用它的时候,解释器会用__repr__
作为替代。
特殊方法一览
跟运算符无关的特殊方法

跟运算符相关的特殊方法

为什么len不是普通方法
如果x
是一个内置类型的实例,那么len(x)的速度会非常快。背后的原因是CPython会直接从一个C结构体里读取对象的长度,完全不会调用任何方法。获取一个集合中元素的数量是一个很常见的操作,在str、list、memoryview
等类型上,这个操作必须高效。