翻译:《实用的Python编程》06_03_Producers_consumers
目录 | 上一节 (6.2 自定义迭代) | 下一节 (6.4 生成器表达式)
6.3 生产者,消费者和管道
生成器在设置各种生产者/消费者问题(producer/consumer problems)和数据流管道(pipeline)中非常有用。本节将对此进行讨论。
生产者消费者问题
生成器与各种形式的 生产者消费者 问题密切相关。
# Producer
def follow(f):
    ...
    while True:
        ...
        yield line        # Produces value in `line` below
        ...
# Consumer
for line in follow(f):    # Consumes value from `yield` above
    ...
yield 语句生成给  for 语句消费的值。
生成器管道
你可以使用生成器的这方面特性来设置进程管道(类似于 Unix 管道(pipe))。
producer → processing → processing → consumer
进程管道包括初始的数据生产者、中间的处理阶段、最后的消费者。
producer → processing → processing → consumer
def producer():
    ...
    yield item
    ...
通常情况下,生产者是一个生成器,尽管也可以是其它的序列列表。yield 将数据输入管道。
producer → processing → processing → consumer
def consumer(s):
    for item in s:
        ...
消费者是一个 for 循环,获取数据(译注:items)并对数据执行某些操作。
producer → processing → processing → consumer
def processing(s):
    for item in s:
        ...
        yield newitem
        ...
中间的处理阶段同时消费和生产数据。它们可能修改数据流,也可能筛选数据流(丢弃数据)。
producer → processing → processing → consumer
def producer():
    ...
    yield item          # yields the item that is received by the `processing`
    ...
def processing(s):
    for item in s:      # Comes from the `producer`
        ...
        yield newitem   # yields a new item
        ...
def consumer(s):
    for item in s:      # Comes from the `processing`
        ...
设置管道的代码如下:
a = producer()
b = processing(a)
c = consumer(b)
你会发现数据逐渐地流向不同的函数。
练习
对于本练习,stocksim.py 程序仍需要在后台运行。并且,你将使用到上一节练习(译注:练习 6.7)编写的  follow()  函数。
练习 6.8:创建一个简单的管道
让我们来看看管道的思想。请创建下面这个函数:
>>> def filematch(lines, substr):
        for line in lines:
            if substr in line:
                yield line
>>>
filematch()  函数除了不再打开文件,几乎与上一节练习的第一个生成器示例完全相同——仅仅对作为参数给出的行序列进行操作。现在,请尝试如下操作:
>>> from follow import follow
>>> lines = follow('Data/stocklog.csv')
>>> ibm = filematch(lines, 'IBM')
>>> for line in ibm:
        print(line)
... wait for output ...
虽然输出可能需要一定时间才会出现,但是,最后你一定会看到包含 IBM 数据的行。
练习 6.9:创建一个复杂的管道
通过执行更多操作来进一步理解管道的思想。
>>> from follow import follow
>>> import csv
>>> lines = follow('Data/stocklog.csv')
>>> rows = csv.reader(lines)
>>> for row in rows:
        print(row)
['BA', '98.35', '6/11/2007', '09:41.07', '0.16', '98.25', '98.35', '98.31', '158148']
['AA', '39.63', '6/11/2007', '09:41.07', '-0.03', '39.67', '39.63', '39.31', '270224']
['XOM', '82.45', '6/11/2007', '09:41.07', '-0.23', '82.68', '82.64', '82.41', '748062']
['PG', '62.95', '6/11/2007', '09:41.08', '-0.12', '62.80', '62.97', '62.61', '454327']
...
这非常有趣。你在这里可以看到, follow() 函数的输出被传递到 csv.reader()函数,并且,我们现在得到了一系列拆分的行。
练习 6.10:创建更多管道组件
让我们把这样的思想扩展到更大的管道中。首先,创建 ticker.py 文件,然后在 ticker.py 文件里面创建一个函数,像上面一样读取 CSV 文件:
# ticker.py
from follow import follow
import csv
def parse_stock_data(lines):
    rows = csv.reader(lines)
    return rows
if __name__ == '__main__':
    lines = follow('Data/stocklog.csv')
    rows = parse_stock_data(lines)
    for row in rows:
        print(row)
接着,创建一个选择特定列的新函数:
# ticker.py
...
def select_columns(rows, indices):
    for row in rows:
        yield [row[index] for index in indices]
...
def parse_stock_data(lines):
    rows = csv.reader(lines)
    rows = select_columns(rows, [0, 1, 4])
    return rows
再次运行程序,你应该可以看到输出缩小如下:
['BA', '98.35', '0.16']
['AA', '39.63', '-0.03']
['XOM', '82.45','-0.23']
['PG', '62.95', '-0.12']
...
再接着,创建一个生成器函数以转换数据类型并构建字典。示例:
# ticker.py
...
def convert_types(rows, types):
    for row in rows:
        yield [func(val) for func, val in zip(types, row)]
def make_dicts(rows, headers):
    for row in rows:
        yield dict(zip(headers, row))
...
def parse_stock_data(lines):
    rows = csv.reader(lines)
    rows = select_columns(rows, [0, 1, 4])
    rows = convert_types(rows, [str, float, float])
    rows = make_dicts(rows, ['name', 'price', 'change'])
    return rows
...
再次运行程序,你应该能够看到像下面这样的字典流:
{ 'name':'BA', 'price':98.35, 'change':0.16 }
{ 'name':'AA', 'price':39.63, 'change':-0.03 }
{ 'name':'XOM', 'price':82.45, 'change': -0.23 }
{ 'name':'PG', 'price':62.95, 'change':-0.12 }
...
练习 6.11:筛选数据
创建一个筛选数据的函数。示例:
# ticker.py
...
def filter_symbols(rows, names):
    for row in rows:
        if row['name'] in names:
            yield row
使用该函数可以筛选出投资组合中的股票:
import report
portfolio = report.read_portfolio('Data/portfolio.csv')
rows = parse_stock_data(follow('Data/stocklog.csv'))
rows = filter_symbols(rows, portfolio)
for row in rows:
    print(row)
练习 6.12:整合所有的代码
请在 ticker.py 文件中编写函数 ticker(portfile, logfile, fmt) ,该函数根据给定的投资组合、日志文件和表格格式创建实时的股票报价器。示例:
>>> from ticker import ticker
>>> ticker('Data/portfolio.csv', 'Data/stocklog.csv', 'txt')
      Name      Price     Change
---------- ---------- ----------
        GE      37.14      -0.18
      MSFT      29.96      -0.09
       CAT      78.03      -0.49
        AA      39.34      -0.32
...
>>> ticker('Data/portfolio.csv', 'Data/stocklog.csv', 'csv')
Name,Price,Change
IBM,102.79,-0.28
CAT,78.04,-0.48
AA,39.35,-0.31
CAT,78.05,-0.47
...
讨论
心得体会:你可以创建各种生成器函数,并把它们链接在一起执行涉及数据流的管道处理。另外,你可以创建一个函数,把一系列的管道阶段打包到一个单独的函数中调用(例如 parse_stock_data() 函数)。
目录 | 上一节 (6.2 自定义迭代) | 下一节 (6.4 生成器表达式)
注:完整翻译见 https://github.com/codists/practical-python-zh
翻译:《实用的Python编程》06_03_Producers_consumers的更多相关文章
- 翻译:《实用的Python编程》InstructorNotes
		实用的 Python 编程--讲师说明 作者:戴维·比兹利(David Beazley) 概述 对于如何使用我的课程"实用的 Python 编程"进行教学的问题,本文档提供一些通用 ... 
- 翻译:《实用的Python编程》README
		欢迎光临 大约 25 年前,当我第一次学习 Python 时,发现 Python 竟然可以被高效地应用到各种混乱的工作项目上,我立即被震惊了.15 年前,我自己也将这种乐趣教授给别人.教学的结果就是本 ... 
- 翻译:《实用的Python编程》05_02_Classes_encapsulation
		目录 | 上一节 (5.1 再谈字典) | 下一节 (6 生成器) 5.2 类和封装 创建类时,通常会尝试将类的内部细节进行封装.本节介绍 Python 编程中有关封装的习惯用法(包括私有变量和私有属 ... 
- 翻译:《实用的Python编程》04_02_Inheritance
		目录 | 上一节 (4.1 类) | 下一节 (4.3 特殊方法) 4.2 继承 继承(inheritance)是编写可扩展程序程序的常用手段.本节对继承的思想(idea)进行探讨. 简介 继承用于特 ... 
- 翻译:《实用的Python编程》01_02_Hello_world
		目录 | 上一节 (1.1 Python) | 下一节 (1.3 数字) 1.2 第一个程序 本节讨论有关如何创建一个程序.运行解释器和调试的基础知识. 运行 Python Python 程序始终在解 ... 
- 翻译:《实用的Python编程》03_03_Error_checking
		目录 | 上一节 (3.2 深入函数) | 下一节 (3.4 模块) 3.3 错误检查 虽然前面已经介绍了异常,但本节补充一些有关错误检查和异常处理的其它细节. 程序是如何运行失败的 Python 不 ... 
- 翻译:《实用的Python编程》03_04_Modules
		目录 | 上一节 (3.3 错误检查) | 下一节 (3.5 主模块) 3.4 模块 本节介绍模块的概念以及如何使用跨多个文件的函数. 模块和导入 任何一个 Python 源文件都是一个模块. # f ... 
- 翻译:《实用的Python编程》03_05_Main_module
		目录 | 上一节 (3.4 模块) | 下一节 (3.6 设计讨论) 3.5 主模块 本节介绍主程序(主模块)的概念 主函数 在许多编程语言中,存在一个主函数或者主方法的概念. // c / c++ ... 
- 翻译:《实用的Python编程》04_01_Class
		目录 | 上一节 (3.6 设计讨论) | 下一节 (4.2 继承) 4.1 类 本节介绍 class 语句以及创建新对象的方式. 面向对象编程(OOP) 面向对象编程是一种将代码组织成对象集合的编程 ... 
随机推荐
- /usr/lib/nvidia-384/libEGL.so.1 is not a symbolic link
			记得要将384改为自己系统对应的a. sudo mv /usr/lib/nvidia-384/libEGL.so.1 /usr/lib/nvidia-384/libEGL.so.1.org sudo ... 
- 读写 LED 作业 台灯的 频闪研究1
			读写 LED 作业 台灯的 频闪研究: 核心提示: 随着科技的持续发展,目前已经商业化的照明产品从第一代的白炽灯: 第二代的荧光灯.卤灯: 第三代的高强度气体放电灯; 以及当下主流的, 第四代的发光二 ... 
- 高阶函数 HOF & 高阶组件 HOC
			高阶函数 HOF & 高阶组件 HOC 高阶类 js HOC 高阶函数 HOF 函数作为参数 函数作为返回值 "use strict"; /** * * @author x ... 
- Versatile Python 3.x
			Versatile Python 3.x TryPython Python 3.8.0 (default, Nov 14 2019, 22:29:45) [GCC 5.4.0 20160609] on ... 
- H5 下拉刷新、加载更多
			H5 下拉刷新.加载更多 demos const autoLoadMore = (url = ``) => { // todo ... } refs xgqfrms 2012-2020 www. ... 
- Taro Advanced
			Taro Advanced aro 代码与小程序代码混写 https://nervjs.github.io/taro/docs/hybrid.html https://github.com/NervJ ... 
- taro scroll tabs 滚动标签 切换
			taro scroll tabs 滚动标签 切换 https://www.cnblogs.com/lml-lml/p/10954069.html https://developers.weixin.q ... 
- C++算法代码——选举学生会
			题目来自:https://www.luogu.com.cn/problem/P1271 题目描述 学校正在选举学生会成员,有 n(n\le 999)n(n≤999) 名候选人,每名候选人编号分别从 1 ... 
- 《Activity显示界面历险记》—说说View的那些理不清的关系
			前言 在Activity显示View的过程中,有一些重要的角色总让人理不清,比如PhoneWindow.DecorView.ViewRootImpl. 也常常有面试题会问到,他们四者之间的关系?创建的 ... 
- windows server2012 搭建FTP服务器过程
			搭建过程链接地址:https://blog.csdn.net/smalllu161226/article/details/53887751 1.打开windows server2012R2 服务器管理 ... 
