第二章 类型

 — 

类型

基本环境

名字空间

Python 中,每个模块(源码文件)有一个全局名字空间,根据代码作用域,有当前名字(本地名字)空间,如果直接在模块级别执行,本地名字空间和全局名字空间没有区别,但在函数内,当前名字空间指函数作用域指的是函数作用域

Category: python3-note Tags:

21 元类

 — 

类元编程是指在运行时创建或定制类的技艺,在 Python 中,类是一等对象,因此任何时候都可以使用函数新建类,无需使用 class 关键字。类装饰器也是函数,不公审查,修改甚至可以把被装饰类替换成其它类。最后,元类是类元编程最高级的工具,使用元类可以创建具有某种特质的全新类种,例如我们见过的抽象基类

类工厂函数

标准库的一个类工厂函数 -- collections.namedtuple。我们把一个类名和几个属性名传给这个函数,它会创建一个 tuple 的子类,其中元素通过名称获取,还为调试提供了友好的字符串表示(__repr__

Category: fluent_python Tags:

20 属性描述符

 — 

我们上一章使用特性工厂函数编程模式避免重复写读值和设值方法,这里继续,把 quantity 特性工厂函数重构为 Quantity 描述符类

LineItem 类第三版:一个简单的描述符

实现了 __get__, __set____delete__ 方法的类是描述符。描述符的用法是,创建一个实例,作为另一个类的属性

我们将定义一个 Quantity 描述符,LineItem 会用到两个 Quantity 实例,一个管理 weight 属性,一个管理 price 属性。

Quantity 实例是 LineItem 类的属性。

Category: fluent_python Tags:

19 动态属性和特性

 — 

Python 中,数据的属性和处理数据的方法统称属性(attribute)。其实,方法只是可调用的属性。除了这二者之外,我们还可以创建特性(property),在不改变类接口的前提下,使用存取方法(即读值方法和设值方法)修改数据属性。

除了特性,Python 还提供了丰富的 API,用于控制属性的访问权限,以及实现动态属性。使用点号访问属性时,Python 会调用特殊的方法(如 __getattr____setattr__)计算属性。用户自定义的类可以通过 __getattr__ 方法实现 “虚拟属性”,当访问不存在的属性时,即时计算属性值

动态创建属性是一种元变成,框架作者经常这么做,在 Python 中,这种技术很简单,任何人都可以使用,甚至在日常数据转换任务都能用到

使用动态属性转换数据

我们编写个脚本下载 OSCON 数据源,这是一份 JSON 数据,我们后面来解析它:

Category: fluent_python Tags:

18 asyncio

 — 

17 并行

 — 

为了高效处理网络 I/O,需要使用并发,因为网络有很高的延时,为了不浪费 CPU 周期去等待,最好在收到网络相应之前做些其他的事

我们首先看依次从网络下载的代码:

Category: fluent_python Tags:

16 协程

 — 

字典中 to yield 表示产出和让步,对于 Python 生成器中的 yield 来说,这是成立的,yield item 这行代码会产生一个值,提供给 next(...) 调用方,此外,还会做出让步,暂停执行生成器,让调用方继续工作,直到需要使用另一个值再调用 next()。调用方会从生成器中拉取值

语法上来说,协程和生成器类似,都是定义体中包含 yield 关键字的函数,可是,在协程中,yield 通常出现在表达式的右边,可以产出值,也可以不产出 -- 如果 yield 关键字后面没有表达式,那么生成器产出 None,协程可能会从调用方接收数据,不过调用方把数据提供给协程使用的是 .send(datum) 方法,而不是 next(...) 函数。通常调用方会把值推送给协程

yield 关键字甚至还可以不接收或传出数据,不过数据如何流动,yield 都是一种流程控制工具,使用它可以实现协作式多任务:协程可以把控制器让步给中心调度程序,从而激活其他的协程

从根本上把 yield 视作控制流程的方式,这样就好理解协程了

本书前面介绍生成器函数作用不大,但是进行一系列功能改进后,得到了 Python 协程。了解 Python 协程有助于理解各个阶段的改进的功能和复杂度

本章覆盖以下话题:

  • 生成器作为协程使用时的行为和状态
  • 使用装饰器自动预激协程
  • 调用方如何使用生成器对象的 .close() 和 .throw(...) 方法控制协程
  • 协程终止时如何返回值
  • yield from 新语法的用途和语义
  • 使用案例 -- 使用协程管理仿真系统中的并发活动

生成器如何进化成协程

在 Python 2.5 中实现了 yield 关键字可以在表达式中使用,并在生成器 API 中增加了 .send(value) 方法。生成器的调用可以使用 .send(...) 方法发送数据,发送的数据会称为生成器函数中 yield 表达式的值,因此生成器可以作为协程使用,协程指的是一个过程,这个过程与调用方协作,产出由调用方提供的值

Category: fluent_python Tags:

15 with 和 else 语句

 — 

本章讨论其他语言不常见的流程控制,用户可能会忽略这些特性:

  • with 语句和上下文管理器
  • for while 和 try 语句的 else 子句

with 语句会设置一个临时的上下文,交给上下文管理器对象控制,并负责清理上下文。这么做能避免错误并减少样板代码,因此 API 更安全,更易于使用。除了自动关闭文件之外,with 块还有很多用途

else 子句和 with 没关系,不过这两个都内容比较短,所以放到了一个逻辑

先做这个,再做那个: if 之外的 else 块

else 子句不仅能在 if 语句中使用,还能在 for,while,try 语句中使用

else 子句行为如下:

for: 仅当 for 循环运行完毕时(即 for 循环没有被 break 语句终止)才运行 else

try: 仅当 try 块中没有异常时候才运行 else 块,else 子句抛出的异常不会由前面的 except 子句处理

在所有情况下,如果异常或者 return, break 或 continue 语句导致控制权跳到了复合语句之外,else 也会被跳过

for 循环用 else 如下:

Category: fluent_python Tags:

14 可迭代对象,迭代器和生成器

 — 

所有生成器都是迭代器,因为生成器完全实现了迭代器接口,不过迭代器一般用于从集合取出元素,生成器用于 “凭空” 创造元素。斐波那契数列例子可以很好的说明两者区别:斐波那契数列中的数有无穷个,在一个集合里放不下。

在 Python 3 中,生成器有广泛用途。现在即使是内置的 range() 函数也要返回一个类似生成器的对象,而以前返回完整列表。如果一定让 range() 函数返回列表,必须明确指明(例如,list(range(100)))。

在 Python 中,所有集合都能迭代。在 Python 内部,迭代器用于支持:

  • for 循环
  • 构建和扩展集合类型
  • 逐行遍历文本文件
  • 列表推导,字典推导和集合推导
  • 元组拆包
  • 调用函数时,使用 * 拆包

本章探讨以下话题:

  • 语言内部使用 iter(...) 内置函数处理可迭代对象的方式
  • 如何使用 Python 经典的迭代器模式
  • 详细说明生成器函数的工作原理
  • 如何使用生成器函数或生成器表达式代替经典的迭代器
  • 如何使用标准库中通用的生成器函数
  • 如何使用 yield from 语句合并生成器
  • 案例分析: 在一个数据库转换工具中使用生成器处理大型数据集
  • 为什么生成器和协程看似相同,其实差别很大,不能混淆

Sentence 类第 1 版:单词序列

我们创建一个类,并向它传入一些包含文本的字符串,然后可以逐个单词迭代,第 1 版要实现序列协议,这个类的对象可以迭代,因为所有序列都可以迭代 -- 这一点前面已经说过,现在说明真正的原因

下面展示了一个可以通过索引从文本提取单词的类:

Category: fluent_python Tags:

13 运算符重载

 — 

我们本章会讨论:

  • Python 如何处理终追运算符中不同类型的操作数
  • 使用鸭子类型或显式类型检查处理不同类型的操作数
  • 中缀运算符如何表明自己无法处理的操作数
  • 众多比较运算符(如 ==,>,<= 等等)的特殊行为
  • 增量赋值运算符(如 += )的默认处理方式和重载方式

运算符重载基础

在某些圈子里,运算符重载名声不太好,因为总被滥用.Python 加了一些限制,做好了灵活性,可用性和安全性的平衡

  • 不能重载内置运算符
  • 不能新建运算符,只能重载现有的
  • 某些运算符不能重载 -- is,and,or 和 not(不过位运算 &,| 和 ~ 可以)

一元运算符

- (__neg__) 一元取负运算符,如果 x 是 -2, -x == 2

+ (__pos__) 一元取正运算符,通常 x == +x,但也有一些例外

~ (__invert__) 对整数按位去饭,定义 ~x == -(x + 1),如果 x 是 2, ~x == -3

支持一元操作符只需要实现相应的特殊方法,这些方法只有一个 self 参数,然后使用符合所在类的逻辑实现。不过,要遵守运算符的一个基本规则:始终返回一个新对象。也就是不能修改 self

对于 -+ 来说,结果可能是与 self 属于同一类的实例,多数的时候, + 最好返回 self 的副本。abs(...) 的结果应该是一个标量,但是对于 ~ 来说,很难说明什么结果是合理的,因为可能处理的不是整数,例如 ORM 中,SQL WHERE 子句应该返回反集

Category: fluent_python Tags:

© kaka 2016

Powered by Pelican