本书并不是一本完备的Python使用手册,而是会强调Python作为编程语言独有的特性,这些特性或者是只有Python才具备的,或者是在其他大众语言里很少见的。
1.1 一摞Python风格的纸牌
展示如何实现__getitem__和__len__这两个特殊方法,通过这个例子我们能见识到特殊方法的强大。
import collections
Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
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,得到一个纸牌对象
beer_card = Card('7', 'diamonds')
print("利用namedtuple,得到一个纸牌对象")
print(beer_card)
# 查看一叠牌有多少张
deck = FrenchDeck()
print("查看一叠牌有多少张")
print(len(deck))
# 从一叠牌中抽取特定的一张牌,由__getitem__方法提供
# 抽取第一张
print("抽取第一张")
print(deck[0])
# 抽取最后一张
print("抽取最后一张")
print(deck[-1])
#随机抽取一张牌,不需要单独写一个方法
from random import choice
print("随机抽取一张牌")
print(choice(deck))
print(choice(deck))
print(choice(deck))
#因为__getitem__方法,deck类自动支持切片操作
# 最上面三张牌
print("最上面三张")
print(deck[:3])
# 牌面是A的牌
print("牌面是A的牌")
print(deck[12::13])
输出结果:
利用namedtuple,得到一个纸牌对象
Card(rank='7', suit='diamonds')
查看一叠牌有多少张
52
抽取第一张
Card(rank='2', suit='spades')
抽取最后一张
Card(rank='A', suit='hearts')
随机抽取一张牌
Card(rank='J', suit='clubs')
Card(rank='K', suit='diamonds')
Card(rank='J', suit='spades')
最上面三张
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
牌面是A的牌
[Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
1.2如何使用特殊方法
特殊方法的存在是为了被Python解释器调用的,我们自己并不需要调用它们。没有my_object.__len__()这种写法,而应该使用len(my_object)
很多时候,特殊方法的调用是隐式的,比如 for i in x:这个语句,背后其实用的是iter(x),而这个函数的背后则是x.__iter__()方法。
1.2.1 模拟数值类型
实现一个二维向量(vector)类,演示特殊方法 __repr__、__abs__、__add__和__mul__。
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, other):
return Vector(self.x * other, self.y * other)
可以进行向量的运算
>>> v1=Vector(2,4)
>>> v2=Vector(2,1)
>>> v1+v2
Vector(4,5)
>>> v = Vector(3,4)
>>> abs(v)
5.0
>>> v * 3
Vector(9,12)
>>> abs(v*3)
15.0
1.2.2 字符串的表示形式
Python有一个内置的函数叫repr,它能把一个对象用字符串的形式表达出来一边辨认,这就是“字符串的表示形式”。repr就是通过__repr__这个特殊的方法来得到一个对象的字符串表示形式的。
1.3 特殊方法一览表
表1-1:跟运算符无关的特殊方法
| 类别 | 方法名 |
|---|---|
| 字符串字节序列表示形式 | __ repr __ , __ format __ , __ str __ , __ bytes __ |
| 数值转换 | __ abs __ , __ bool __ , __ complex __ , __ int __ , __ float__ , __ hash __ , __ index __ |
| 集合模拟 | __ len __ , __ getitem __ , __ setitem __ , __ delitem __ , __ contains __ |
| 迭代枚举 | __iter __ , __ reversed __ , __ next __ |
| 可调用模拟 | __ call __ |
| 上下文管理 | __ enter __ , __ exit __ |
| 实例创建和销毁 | __ new __ , __ init __ , __ del __ |
| 属性管理 | __ getattr __ , __ getattribute __ , __ setattr __ , __ delattr __ , __ dir __ |
| 属性描述符 | __ get __ , __ set __ , __ delete __ |
| 跟踪相关的服务 | __ prepare __ , __ instancecheck __ , __ subclasscheck __ |
表1-2:跟运算符相关的特殊方法
| 类别 | 方法名和对应的运算符 |
|---|---|
| 一元运算符 | __ neg __ , __ pos __ , __ abs __ |
| 比较运算符 | __ lt __ <, __ le __ <=, __ eq __ ==, __ ne __ !=, __ gt __ > , __ ge __ >=, |
| 算术运算符 | __ add __ + , __ sub __ - , __ mul __ * , __ truediv __ / , __ floordiv __ // __ mod __ % , __ divmod __ divmode() , __ pow __ **或pow() __ round __ round() |
| 反向算数运算符 | __ radd __ , __ rsub __ , __ rmul __ , __ rtruediv __ , __ rfloordiv __ __ rmod __ , __ rdivmod __ , __ rpow __ |
| 增量赋值运算符 | __ iadd __ , __ isub __ , __ imul __ , __ itruediv __ , __ ifloordiv __ __ imod __ , __ idivmod __ , __ ipow __ |
| 位运算符 | __ invert __ ~, __ lshift __ <<, __ rshift __ >>, __ adn __ &, __ or __ |
| 反向位运算符 | __ rlshift __ , __ rrshift __ , __ rand __ , __ rxor __ , __ ror __ |
| 增量赋值位运算符 | __ ilshift __ , __ irshift __ , __ iand __ , __ ixor __ , __ ior __ |