流畅的Python
第一部分 序幕
第 1 章 Python 数据模型
import collections
from random import choice
# 构建简单的类,类名:Card,属性:rank和suit
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]
def sort_strategy(self, card):
suit_rank_map = dict(spades=3, hearts=2, diamonds=1, clubs=0)
rank_idx = FrenchDeck.ranks.index(card.rank)
return rank_idx * len(suit_rank_map) + suit_rank_map[card.suit]
if __name__ == '__main__':
deck = FrenchDeck()
print(len(deck)) # len调用的是__len__
print(deck[-1]) # deck[-1]调用的是__getitem__
print(choice(deck)) # 随机
print(deck[:3]) # 取前三个deck[0],deck[1],deck[2]
print(deck[12::13]) # 从第12开始,再每隔13取一个
# 实现了__getitem__,FrenchDeck就可以迭代了,迭代背后调用了__iter__
for card in deck:
print(card)
print("反向迭代")
for card in reversed(deck):
print(card)
print("按照指定排序策略排序")
for card in sorted(deck, key=deck.sort_strategy):
print(card)
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(self.x or self.y)
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)
if __name__ == '__main__':
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1) # 调用__repr__或__str__;若无,打印类似<__main__.Vector object at 0x1025e4070>
print(str(v1)) # 调用__repr__或__str__;若无,打印类似<__main__.Vector object at 0x1025e4070>
print(v1 + v2) # 调用__add__
print(v1 * 2) # 调用__mul__
print(abs(v2)) # 调用__abs__
print(bool(v1)) # 默认自己定义类的实例是True,若有__bool__、__len__,就逐次调用即判即返回
-
为什么len不是普通方法?
如果x是内置类型实例,len(x) 的速度非常快(CPython直接从C结构体里读取对象的长度) -
推荐书籍
《Python 技术手册》
《Python 参考手册》
《Python Cookbook》
第二部分 数据结构
第 2 章 序列构成的数组
Python 标准库用 C 实现了丰富的序列类型,列举如下。
-
容器序列
list、tuple 和 collections.deque,这些序列能存放不同类型的数据。 -
扁平序列
str、bytes、bytearray、memoryview 和 array.array,这类序列只能容纳一种类型。 -
可变序列
list、bytearray、array.array、collections.deque 和 memoryview。 -
不可变序列
tuple、str 和 bytes。
列表推导
# 把一个字符串变成 Unicode 码位的列表
symbols = '$¢£¥€¤'
# 方式一
codes = []
for symbol in symbols:
codes.append(ord(symbol))
# 方式二(列表推导)
codes = [ord(symbol) for symbol in symbols]
# Python 2.x 和 Python 3.x 列表推导式里的变量作用域对比
Python 2.7.18 (default, Oct 2 2021, 04:20:38)
[GCC Apple LLVM 13.0.0 (clang-1300.0.29.1) [+internal-os, ptrauth-isa=deploymen on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 1
>>> abc = [x for x in 'abc']
>>> x # python 2.x,会被列表推导里的同名变量的值取代
'c'
>>> abc
['a', 'b', 'c']
Python 3.8.9 (default, Oct 26 2021, 07:25:53)
[Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 1
>>> abc = [x for x in 'abc'] # x 在列表推导的局部作用域
>>> x # python 3.x,不会被列表推导里的同名变量的值取代
1
>>> abc
['a', 'b', 'c']
# 列表推导式与map/filter对比
>>> symbols = '$¢£¥€¤'
>>> beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
>>> beyond_ascii
[162, 163, 165, 8364, 164]
>>>
>>> beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))
>>> beyond_ascii
[162, 163, 165, 8364, 164]
# 列表推导计算笛卡儿积
>>> colors = ['black', 'white']
>>> sizes = ['S', 'M', 'L']
>>> tshirts = [(color, size) for color in colors for size in sizes]
>>> tshirts
[('black', 'S'), ('black', 'M'), ('black', 'L'), ('white', 'S'), ('white', 'M'), ('white', 'L')]
生成器表达式
# 用生成器表达式初始化元组和数组
>>> symbols = '$¢£¥€¤'
>>> tuple(ord(symbol) for symbol in symbols)
(36, 162, 163, 165, 8364, 164)
>>> import array
>>> array.array('I', (ord(symbol) for symbol in symbols))
array('I', [36, 162, 163, 165, 8364, 164])
# 使用生成器表达式计算笛卡儿积
>>> colors = ['black', 'white']
>>> sizes = ['S', 'M', 'L']
>>> for tshirt in ('%s %s' % (c, s) for c in colors for s in sizes):
... print(tshirt)
...
black S
black M
black L
white S
white M
white L
元组
>>> coordinates = (1, 2)
>>> city, year = ('Shanghai', 2001)
>>> city_year_list = [('Shanghai', 2001), ('Beijing', 1999)]
>>> for city_year in city_year_list:
... print('%s-%d' % city_year) # 元组拆包
...
Shanghai-2001
Beijing-1999
>>>
>>> for city, _ in city_year_list:
... print(city)
...
Shanghai
Beijing
>>> import os
>>> ret = os.path.split('/home/luciano/.ssh/idrsa.pub')
>>> ret
('/home/luciano/.ssh', 'idrsa.pub')
# 元组拆包
>>> coordinates = (1, 2)
>>> coordinates[0]
1
>>> coordinates[1]
2
>>> x, y = coordinates # 元祖拆包
>>> x
1
>>> y
2
>>> x, y = y, x # 不使用中间变量交换两个变量的值
>>> x
2
>>> y
1
# 元祖拆包
>>> divmod(20, 8)
(2, 4)
>>> t = (20, 8)
>>> divmod(*t)
(2, 4)
>>> quotient, remainder = divmod(*t)
>>> quotient, remainder
(2, 4)
# 用*来处理剩下的元素
>>> a, b, *rest = range(5)
>>> a, b, rest
(0, 1, [2, 3, 4])
>>> a, b, *rest = range(3)
>>> a, b, rest
(0, 1, [2])
>>> a, b, *rest = range(2)
>>> a, b, rest
(0, 1, [])
>>> a, b, *rest = range(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected at least 2, got 1)
>>> a, *body, c, d = range(5)
>>> a, body, c, d
(0, [1, 2], 3, 4)
>>> *head, b, c, d = range(5)
>>> head, b, c, d
([0, 1], 2, 3, 4)
# 嵌套元组拆包
>>> arr = [('Tom', 10, (90, 80)), ('Lucy', 11, (89, 100))]
>>> for name, age, (math_grade, chinese_grade) in arr:
... print(f"{
name}, {
age}, {
math_grade}, {
chinese_grade}")
...
Tom, 10, 90, 80
Lucy, 11, 89, 100
# 具名元组
>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates')
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
>>> tokyo.population
36.933
>>> tokyo.coordinates
(35.689722, 139.691667)
>>> tokyo[1]
'JP'
>>>
>>> City._fields
('name', 'country', 'population', 'coordinates')
>>> LatLong = namedtuple('LatLong', 'lat long')
>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
>>> delhi = City._make(delhi_data)
>>> delhi._asdict()
{
'name': 'Delhi NCR', 'country': 'IN'
《流畅的Python》学习笔记

最低0.47元/天 解锁文章
398

被折叠的 条评论
为什么被折叠?



