流畅的Python笔记

《流畅的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__,就逐次调用即判即返回
   
  • 特殊方法
    https://docs.python.org/3/reference/datamodel.html

  • 为什么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'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值