流畅的Python总览
第一部分 序幕
通过特殊方法,实现一个 13*4 52张的纸牌。
第二部分 数据结构
列表、字典和集合、文本和字节序列,用于放置数据的序列,包括了容器序列(list、tuple、collections.depue,可放置任何类型对象的引用)、扁平序列(基础类型:字符、字节、数值)
第三部分 把函数视作对象
将函数作为一等对象使用。python基础函数(高阶函数、匿名函数、函数式编程)、策略模式与命令模式实现的代码简化、函数的装饰器与闭包的实现。
第四部分 面向对象惯用法
从以下章节(对象引用、可变性和垃圾回收、符合python风格的对象、序列的修改、散列和切片、接口:从协议到抽象基类、继承的优缺点、正确重载运算符)讲解了引用(reference)的原理、“可变性”的概念、实例的生命周期、如何构建自定义的集合类型和ABC、多重继承该怎么理顺、什么时候应该使用操作符重载及其方法。
第五部分 控制流程
通过章节(可迭代的对象、迭代器和生成器、上下文管理器和 else 块、协程、使用期物处理并发、 使用 asyncio 包处理并发),介绍除去如条件判断、循环和子程序之类的顺序控制流程外,如何通过生成器(generator)、上下文管理器(context manager)和协程(coroutine)来介绍这些控制流程的构造,以及处理并发性(collections.futures)和面向事件的 I/O (asyncio)这些类库。
第六部分 元编程
通过动态属性和特性、属性描述符、类元编程,介绍到如何动态创建带属性的类,用以处理诸如JSON 这类半结构化的数据。
本章主要记录 第一部分 序幕,也就是第一章 python数据模型。
python数据模型
python的魔法方法
介绍了python的魔术方法, 它们经常是两个下划线包围来命名的(比如__init__ , __lt__, __len__). 这些特殊方法是为了被python解释器调用的, 这些方法会注册到他们的类型中方法集合中, 相当于为cpython提供抄近路. 这些方法的速度也比普通方法要快, 当然在自己不清楚这些魔术方法的用途时, 不要随意添加。
关于字符串的表现形式是两种, __str__与__rep__ . python的内置函数 repr 就是通过 __repr__这个特殊方法来得到一个对象的字符串表示形式. 这个在交互模式下比较常用, 如果没有实现 __repr__ , 当控制台打印一个对象时往往是 <A object at 0x000> . 而 __str__ 则是 str() 函数时使用的, 或是在 print 函数打印一个对象的时候才被调用, 终端用户友好。
两者还有一个区别, 在字符串格式化时, “%s” 对应了 __str__ . 而 “%r” 对应了 __repr__. __str__和 __repr__ 在使用上比较推荐的是,前者是给终端用户看,而后者则更方便我们调试和记录日志
python风格代码实现的纸牌
import collections
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]
- collections.namedtuple
Python 2.6 开始,namedtuple 就加入到 Python 里,用以构建只有少数属性但是没有方法的对象。如以上代码构建了类名为:Card,属性包含:rank 、suit的一个简单类。 - __ getitem__ 方法
因为__ getitem__ 方法把 [] 操作交给了 self._cards 列表,然后就把这个[]索引操作给设定下来了,因为self._cards是列表,所以列表支持索引、支持反向索引、还支持迭代 如果没有实现这个方法就会报错:‘FrenchDeck’ object does not support indexing - 随机抽牌 random.choice
>>> from random import choice
>>> choice(deck)
Card(rank='3', suit='hearts')
>>> choice(deck)
Card(rank='K', suit='spades')
>>> choice(deck)
Card(rank='2', suit='clubs')
纸牌排序
import collections
Card = collections.namedtuple('Card',['rank','suit'])
# 定义花色大小
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
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 spades_high(card):
rank_value = FrenchDeck.ranks.index(card.rank)
return rank_value * len(suit_values) + suit_values[card.suit]
- 纸牌排序
FrenchDeck 是不能洗牌的,因为这摞牌是不可变的(immutable):卡牌和它们的位置都是固定的,除非我们破坏这个类的封装性,直接对 _cards 进行操作。