目录 | 上一节 (2.7 对象模型) | 下一节 (3.2 深入函数)

3.1 脚本

在该部分,我们将深入研究编写 Python 脚本的惯例。

什么是脚本?

脚本就是运行和终止一系列语句的程序。

# program.py

statement1
statement2
statement3
...

到目前为止,我们主要在编写脚本。

问题

如果你编写一个有用的脚本,它的特性和功能将会增加。你可能想要将其应用于相关的问题。随着时间的推移,它可能会成为一个关键的应用程序。如果你不注意的话,它可能会变成一团乱麻。因此,让我们有条理的组织程序吧。

定义变量

名称必须在使用之前定义。

def square(x):
return x*x a = 42
b = a + 2 # Requires that `a` is defined z = square(b) # Requires `square` and `b` to be defined

顺序很重要。

几乎总是把变量和函数的定义放到顶部附近。

定义函数

把所有与单个任务相关的代码都放到一个地方是个好主意。可以使用函数实现:

def read_prices(filename):
prices = {}
with open(filename) as f:
f_csv = csv.reader(f)
for row in f_csv:
prices[row[0]] = float(row[1])
return prices

函数也可以简化重复的操作。

oldprices = read_prices('oldprices.csv')
newprices = read_prices('newprices.csv')

什么是函数?

函数是命名的语句序列。

def funcname(args):
statement
statement
...
return result

任何 Python 语句都可以在函数内部使用。

def foo():
import math
print(math.sqrt(2))
help(math)

Python 中没有特殊语句(这使它很容易记住)。

函数定义

可以按任何顺序定义函数。

def foo(x):
bar(x) def bar(x):
statements # OR
def bar(x):
statements def foo(x):
bar(x)

在程序执行期间,函数必须在实际使用之前(调用)定义。

foo(3)        # foo must be defined already

在文体上,函数以自底向上的方式定义可能更常见。

自底向上的风格

函数被当做构建块。较小/较简单的块优先。

# myprogram.py
def foo(x):
... def bar(x):
...
foo(x) # Defined above
... def spam(x):
...
bar(x) # Defined above
... spam(42) # Code that uses the functions appears at the end

后面的函数基于前面的函数构建。再次说明,这仅仅是一种风格问题。在上面程序中唯一重要的事情是 spam(42) 的调用是在最后一步。

函数设计

理想情况下,函数应该是一个黑盒。它们应该仅对输入进行操作,并避免全局变量和奇怪的副作用。首要目标:模块化和可预测性。

文档字符串

以文档字符串(doc-string)的形式包含文档是良好的实践。文档字符串是紧接着函数名的字符串。它们用于 help() 函数,集成开发环境和其它的工具。

def read_prices(filename):
'''
Read prices from a CSV file of name,price data
'''
prices = {}
with open(filename) as f:
f_csv = csv.reader(f)
for row in f_csv:
prices[row[0]] = float(row[1])
return prices

一个好的文档字符串实践是写一句简短的话总结该函数做什么。如果需要更多的信息,请包含一个简短的带有更详细的参数说明的使用示例,

类型注解

也可以添加可选的类型提示到函数定义中。

def read_prices(filename: str) -> dict:
'''
Read prices from a CSV file of name,price data
'''
prices = {}
with open(filename) as f:
f_csv = csv.reader(f)
for row in f_csv:
prices[row[0]] = float(row[1])
return prices

提示在操作上什么也不做。它们纯粹是信息性的。但是,集成开发工具,代码检查器,以及其它工具可能会使用它来执行更多的操作。

练习

在第 2 节中,编写了一个名为 report.py 的程序,该程序可以打印出显示股票投资组合绩效的报告。此程序包含一些函数。例如:

# report.py
import csv def read_portfolio(filename):
'''
Read a stock portfolio file into a list of dictionaries with keys
name, shares, and price.
'''
portfolio = []
with open(filename) as f:
rows = csv.reader(f)
headers = next(rows) for row in rows:
record = dict(zip(headers, row))
stock = {
'name' : record['name'],
'shares' : int(record['shares']),
'price' : float(record['price'])
}
portfolio.append(stock)
return portfolio
...

但是,程序的有些部分仅执行一系列的脚本计算。这些代码出现在程序结尾处。例如:

...

# Output the report

headers = ('Name', 'Shares', 'Price', 'Change')
print('%10s %10s %10s %10s' % headers)
print(('-' * 10 + ' ') * len(headers))
for row in report:
print('%10s %10d %10.2f %10.2f' % row)
...

在本练习中,我们使用函数来对该程序进行有条理的组织,使程序更健壮。

练习 3.1:将程序构造为函数的集合

请修改 report.py 程序,以便所有主要操作(包括计算和输出)都由一组函数执行。特别地:

  • 创建打印报告的函数 print_report(report)
  • 修改程序的最后一部分,使其仅是一系列函数调用,而无需进行其它运算。

练习 3.2:为程序执行创建一个顶层函数

把程序的最后一部分打包到单个函数 portfolio_report(portfolio_filename, prices_filename) 中。让程序运行,以便下面的函数调用像之前一样创建报告。

portfolio_report('Data/portfolio.csv', 'Data/prices.csv')

在最终版本中,程序只不过是一系列函数定义,最后是对单个函数portfolio_report() 的调用(它执行程序中涉及的所有步骤)。

通过将程序转换为单个函数,在不同的输入后可以很轻松地运行它。例如,在运行程序后以交互方式尝试这些语句:

>>> portfolio_report('Data/portfolio2.csv', 'Data/prices.csv')
... look at the output ...
>>> files = ['Data/portfolio.csv', 'Data/portfolio2.csv']
>>> for name in files:
print(f'{name:-^43s}')
portfolio_report(name, 'Data/prices.csv')
print() ... look at the output ...
>>>

说明

Python 使在有一系列语句的文件中编写相对无结构的脚本变得很轻松。总体来说,无论何时,尽可能地利用函数通常总是更好的选择。在某些时候,脚本会不断增加,并且我们希望它更有组织。另外,一个鲜为人知的事实是,如果使用函数,Python 的运行会更快一些。

目录 | 上一节 (2.7 对象模型) | 下一节 (3.2 深入函数)

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

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

  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. Eclipse无法查看Servlet源代码的解决方案

    在Apache官方网站中选择你对应的tomacat版本下载对应的Tomcat的源码 下载Source Code Distributions下的zip 将下载的zip文件复制到lib文件夹下 在提示页面 ...

  2. F - To Add Which?

    Description There is an integer sequence with N integers. You can use 1 unit of cost to increase any ...

  3. Codeforces Round #650 (Div. 3) E. Necklace Assembly (暴力)

    题意:有一个字符串,要求使用其中字符构造一个环(不必全部都用),定义一个环是k美的,如果它转\(k\)次仍是原样,现在给你\(k\),要求最长的k美环的长度. 题解:我们首先看\(k\),如果一个环转 ...

  4. PowerShell随笔4---变量

    全局变量 输入$global:后按ctrl+space,我们就可以看到所有的全局变量. 比如我们可以查看PowerShell的版本: 我们可以在在编写脚本代码的时候使用这些变量,globle可以省略, ...

  5. CF1474-A. Puzzle From the Future

    CF1474-A. Puzzle From the Future 题意: 有两个由\(0,1\)组成的.长度相等字符串\(a, b\),两个字符串按位相加得到一个新的字符串\(s\),对\(s\)取\ ...

  6. Python——Django框架——django-simple-captcha(验证码)

    一.引用 包 pip install django-simple-captcha 二.将captcha加入setting的 INSTALLED_APPS 三.运行python manager.py m ...

  7. 操作系统 part1

    实验好多,人好累... 一.进程和线程 references: 进程三种基本状态 进程和线程的概念.区别和联系 进程和线程的主要区别(总结) 进程间通信IPC 1.进程 进程,是资源分配和调度的基本单 ...

  8. 快速搞懂.NET 5/.NET Core应用程序的发布部署

    .NET Framework时代,.NET 应用程序大多直接部署运行在Windows服务器上,当然也可以通过Mono部署运行在Linux上.无论部署exe,还是IIS站点.或是Windows Serv ...

  9. Apple Watch Series 6 无法使用截屏问题和解决方案

    Apple Watch Series 6 无法使用截屏问题和解决方案 shit Apple,无法使用截屏, TMD 根本就不存在 相机胶卷 ! 不好使 解决方案 ??? https://support ...

  10. UTM & User Tracking Message

    UTM & User Tracking Message utm_source https://marketingplatform.google.com/about/resources/link ...