目录 | 上一节 (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