目录 | 上一节 (3.5 主模块) | 下一节 (4 类)

3.6 设计讨论

本节,我们重新考虑之前所做的设计决策。

文件名与可迭代对象

考虑以下两个返回相同输出的程序。

# Provide a filename
def read_data(filename):
records = []
with open(filename) as f:
for line in f:
...
records.append(r)
return records d = read_data('file.csv')
# Provide lines
def read_data(lines):
records = []
for line in lines:
...
records.append(r)
return records with open('file.csv') as f:
d = read_data(f)
  • 你更倾向于使用哪个函数?为什么?
  • 哪个函数更灵活?

鸭子类型(Duck Typing)

在计算机程序设计中,鸭子类型 用于确定一个对象是否可用于特定目的。这是 鸭子测试 的一种应用。

如果它看起来像鸭子、游泳像鸭子、叫声像鸭子,那么它可能就是只鸭子。

上述第二个 read_data() 函数接受任何可迭代对象,而不仅是文件行。

def read_data(lines):
records = []
for line in lines:
...
records.append(r)
return records

这意味着我们可以使用它处理其它的行(lines)

# A CSV file
lines = open('data.csv')
data = read_data(lines) # A zipped file
lines = gzip.open('data.csv.gz','rt')
data = read_data(lines) # The Standard Input
lines = sys.stdin
data = read_data(lines) # A list of strings
lines = ['ACME,50,91.1','IBM,75,123.45', ... ]
data = read_data(lines)

这种设计具有很大的灵活性。

问题:我们应该拥抱还是反对这种灵活性?

库设计最佳实践

通常,拥抱灵活性可以更好的服务于代码库。不要限制你的选择,灵活性大,带来的威力也大。

练习

练习 3.17:从文件名到类文件对象

现在,你已经创建了一个包含 parse_csv() 函数的 fileparse.py 文件。parse_csv() 函数像下面这样工作:

>>> import fileparse
>>> portfolio = fileparse.parse_csv('Data/portfolio.csv', types=[str,int,float])
>>>

虽然函数接受的是一个文件名,但是,你可以使代码更具灵活性。请求修改函数,以便它可以接受任何类文件或者可迭代对象。例如:

>>> import fileparse
>>> import gzip
>>> with gzip.open('Data/portfolio.csv.gz', 'rt') as file:
... port = fileparse.parse_csv(file, types=[str,int,float])
...
>>> lines = ['name,shares,price', 'AA,100,34.23', 'IBM,50,91.1', 'HPE,75,45.1']
>>> port = fileparse.parse_csv(lines, types=[str,int,float])
>>>

在新的代码中,如果像以前一样传递一个文件名会发生什么?

>>> port = fileparse.parse_csv('Data/portfolio.csv', types=[str,int,float])
>>> port
... look at output (it should be crazy) ...
>>>

正如上面代码显示的那样,这可能带来意想不到的结果,所以,修改的时候需要小心一些。你可以添加安全检查来避免这种情况吗?

练习 3.18:修复(fix)现有函数

请修复 report.py 文件中的 read_portfolio()read_prices() 函数。以便它们可以使用修改后的 parse_csv() 函数。这应该只涉及较小的修改。之后,report.pypcost.py 程序应能够像以往一样工作。

目录 | 上一节 (3.5 主模块) | 下一节 (4 类)

注:完整翻译见 https://github.com/codists/practical-python-zh

翻译:《实用的Python编程》03_06_Design_discussion的更多相关文章

  1. 翻译:《实用的Python编程》InstructorNotes

    实用的 Python 编程--讲师说明 作者:戴维·比兹利(David Beazley) 概述 对于如何使用我的课程"实用的 Python 编程"进行教学的问题,本文档提供一些通用 ...

  2. 翻译:《实用的Python编程》README

    欢迎光临 大约 25 年前,当我第一次学习 Python 时,发现 Python 竟然可以被高效地应用到各种混乱的工作项目上,我立即被震惊了.15 年前,我自己也将这种乐趣教授给别人.教学的结果就是本 ...

  3. 翻译:《实用的Python编程》05_02_Classes_encapsulation

    目录 | 上一节 (5.1 再谈字典) | 下一节 (6 生成器) 5.2 类和封装 创建类时,通常会尝试将类的内部细节进行封装.本节介绍 Python 编程中有关封装的习惯用法(包括私有变量和私有属 ...

  4. 翻译:《实用的Python编程》04_02_Inheritance

    目录 | 上一节 (4.1 类) | 下一节 (4.3 特殊方法) 4.2 继承 继承(inheritance)是编写可扩展程序程序的常用手段.本节对继承的思想(idea)进行探讨. 简介 继承用于特 ...

  5. 翻译:《实用的Python编程》01_02_Hello_world

    目录 | 上一节 (1.1 Python) | 下一节 (1.3 数字) 1.2 第一个程序 本节讨论有关如何创建一个程序.运行解释器和调试的基础知识. 运行 Python Python 程序始终在解 ...

  6. 翻译:《实用的Python编程》03_03_Error_checking

    目录 | 上一节 (3.2 深入函数) | 下一节 (3.4 模块) 3.3 错误检查 虽然前面已经介绍了异常,但本节补充一些有关错误检查和异常处理的其它细节. 程序是如何运行失败的 Python 不 ...

  7. 翻译:《实用的Python编程》03_04_Modules

    目录 | 上一节 (3.3 错误检查) | 下一节 (3.5 主模块) 3.4 模块 本节介绍模块的概念以及如何使用跨多个文件的函数. 模块和导入 任何一个 Python 源文件都是一个模块. # f ...

  8. 翻译:《实用的Python编程》03_05_Main_module

    目录 | 上一节 (3.4 模块) | 下一节 (3.6 设计讨论) 3.5 主模块 本节介绍主程序(主模块)的概念 主函数 在许多编程语言中,存在一个主函数或者主方法的概念. // c / c++ ...

  9. 翻译:《实用的Python编程》04_01_Class

    目录 | 上一节 (3.6 设计讨论) | 下一节 (4.2 继承) 4.1 类 本节介绍 class 语句以及创建新对象的方式. 面向对象编程(OOP) 面向对象编程是一种将代码组织成对象集合的编程 ...

随机推荐

  1. 牛客小白月赛28 J.树上行走 (并查集,dfs)

    题意:有\(n\)个点,\(n-1\)条边,每个点的类型是\(0\)或\(1\),现在让你选一个点,然后所有与该点类型不同的点直接消失,问选哪些点之后,该点所在的联通块最大. 题解: 因为选完之后两个 ...

  2. F(x) HDU - 4734

    题意: 给你一个n位的数x(A(n)A(n-1)...A(1)),那么F(x)=A(n)*2^(n-1)+A(n-1)*2^(n-2)......+A(1)*2^(0) 题目输入A.B 你需要找出来在 ...

  3. 开源RPA软件试用

      优点 缺点 其它 Robot Framework 可视化界面 运行环境搭建复杂,依赖较多 操作复杂 倾向于自动化测试 TagUI 浏览器支持好 官方文档详细 命令行操作 非浏览器程序支持一般   ...

  4. Django用户注册、登录

    一.用户注册 1 ''' 2 注册的表单模型 3 forms.py 的例子 4 ''' 5 6 from django import forms #表单功能 7 from django.contrib ...

  5. OpenStack Train版-11.安装horizon服务(计算节点)

    OpenStack仪表板Dashboard服务的项目名称是Horizon,它所需的唯一服务是身份服务keystone,开发语言是python的web框架Django. 安装Train版本的Horizo ...

  6. Redis 持久化(Persistence)

    作为内存数据库,Redis 依然提供了持久化机制,其主要目的有两个: 安全:保证进程崩溃后数据不会丢失 备份:方便数据迁移与快速恢复 Redis 同时提供两种持久化机制: RDB 快照:数据库在某个时 ...

  7. Leetcode(82)-删除排序链表中的重复元素 II

    给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字. 示例 1: 输入: 1->2->3->3->4->4->5 输出: 1-&g ...

  8. spring-cloud-eureka-client-consumer

    服务注册中心eureka-server已经搭好,并且SPRING-CLOUD-NETFLIX-EUREKA-CLIENT-APPLICATION提供一个hello服务 编写一个eureka-clien ...

  9. js 如何取消promise

    1: 使用reject function hello() { let _res, _rej: any; const promise = new Promise((res, rej) => { _ ...

  10. django中间件介绍

    在学习django中间件之前,先来认识一下django的生命周期,如下图所示: django生命周期:浏览器发送的请求会先经过wsgiref模块处理解析出request(请求数据)给到中间件,然后通过 ...