翻译:《实用的Python编程》03_01_Script

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

3.1 脚本

在该部分,咱们将深刻研究编写 Python 脚本的惯例。git

什么是脚本?

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

# program.py

statement1
statement2
statement3
...

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

问题

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

定义变量

名称必须在使用以前定义。模块化

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

函数也能够简化重复的操做。ui

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

相关文章
相关标签/搜索