Files

7.1 KiB
Raw Permalink Blame History

doc_type, full_text
doc_type full_text
short sources/07_Functions.md

07_Functions 总结

本文介绍了 Python 程序组织的基础工具:自定义函数、标准库函数、异常处理,以及如何把脚本改造成可复用、可测试、可从命令行调用的程序。它延续前一节文件处理内容,将 pcost.py 逐步重构为函数式、健壮且更接近真实使用场景的程序。

核心内容

自定义函数

函数用于封装可复用代码。一个函数通常包含:

  • def 关键字定义函数
  • 参数列表接收输入
  • 函数体执行任务
  • return 显式返回结果
  • 可选的文档字符串说明用途

示例:

def sumcount(n):
    '''
    Returns the sum of the first n integers
    '''
    total = 0
    while n > 0:
        total += n
        n -= 1
    return total

调用函数:

a = sumcount(100)

函数是组织较大程序的重要方式,也是代码复用和测试的基础。相关主题可扩展为 python functions、code reuse。

文档字符串

如果函数的第一条语句是字符串,它会成为函数的文档字符串,可以通过 help() 查看。

def greeting(name):
    'Issues a greeting'
    print('Hello', name)

这体现了 Python 中“代码即文档”的轻量实践,可关联 documentation。

标准库函数与模块

Python 自带大型标准库,通过 import 使用模块中的函数和对象。

示例:

import math
x = math.sqrt(10)

import urllib.request
u = urllib.request.urlopen('http://www.python.org/')
data = u.read()

本文只做简要介绍,后续会更深入讨论模块和库。这里强调标准库可以避免重复造轮子,是 Python 实用性的核心来源之一。相关主题:python standard library、modules and imports。

错误与异常

函数通过异常报告错误。未处理的异常会中断函数执行,甚至导致整个程序停止。

示例:

>>> int('N/A')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'N/A'

异常信息通常包含:

  • 发生了什么错误
  • 错误发生的位置
  • traceback,即导致错误的一系列函数调用路径

这些信息对调试非常重要。相关主题:python exceptions、debugging。

捕获和处理异常

异常可以用 try-except 捕获并处理。

for line in file:
    fields = line.split(',')
    try:
        shares = int(fields[1])
    except ValueError:
        print("Couldn't parse", line)

要注意:except 后的异常名称必须匹配实际可能发生的错误类型,例如 ValueError。

本文指出,在实际编程中,很难提前知道所有可能发生的错误。异常处理经常是在程序崩溃后补充的,即发现“忘了处理某类错误”之后再修正。相关主题:error handling、robust programming。

抛出异常

可以用 raise 主动抛出异常。

raise RuntimeError('What a kerfuffle')

如果没有被 try-except 捕获,程序会终止并显示 traceback。

这说明异常不仅是系统自动产生的错误机制,也可以作为程序设计中的显式错误报告工具。相关主题:exception raising。

练习与实践路径

练习 1.29:定义函数

要求定义简单的 greeting(name) 函数,理解:

  • 函数定义
  • 参数传递
  • 函数调用
  • 文档字符串
  • help() 查看函数说明

练习 1.30:把脚本改造成函数

将前一节中的 pcost.py 脚本改造成:

def portfolio_cost(filename):
    ...

该函数接收文件名,读取投资组合数据,并返回总成本。

示例调用:

cost = portfolio_cost('Data/portfolio.csv')
print('Total cost:', cost)

还可以通过交互模式测试:

python3 -i pcost.py

然后调用:

>>> portfolio_cost('Data/portfolio.csv')
44671.15

这一练习强调:将脚本逻辑封装为函数后,代码更容易测试、复用和调试。相关主题:script to function、interactive testing。

练习 1.31:错误处理

当输入文件包含缺失字段时,程序可能崩溃:

ValueError: invalid literal for int() with base 10: ''

练习要求修改 pcost.py:

  • 捕获异常
  • 打印警告信息
  • 跳过坏数据行
  • 继续处理剩余文件

这里引入了处理脏数据的两种策略:

  1. 清理原始输入文件
  2. 修改程序,使其能容忍并处理坏数据

这与现实数据处理高度相关,可关联 data cleaning、fault tolerance。

练习 1.32:使用 csv 标准库

推荐使用 Python 的 csv 模块处理 CSV 文件,而不是手动 split(',')。

示例:

import csv
f = open('Data/portfolio.csv')
rows = csv.reader(f)
headers = next(rows)

csv 模块可以处理许多底层细节,例如:

  • 正确拆分逗号分隔字段
  • 处理引号
  • 去除字段中的双引号
  • 更可靠地解析 CSV 数据

这体现了使用标准库替代手写解析逻辑的价值。相关主题:csv processing、data parsing。

练习 1.33:从命令行读取参数

原始程序中输入文件名被硬编码:

cost = portfolio_cost('Data/portfolio.csv')

练习要求改用 sys.argv 从命令行获取参数:

import sys

if len(sys.argv) == 2:
    filename = sys.argv[1]
else:
    filename = 'Data/portfolio.csv'

cost = portfolio_cost(filename)
print('Total cost:', cost)

sys.argv 是命令行参数列表。这样程序既可以使用默认文件,也可以由用户指定输入文件。

运行方式:

python3 pcost.py Data/portfolio.csv

这一节把程序从“学习用脚本”推进到“可配置命令行工具”的形式。相关主题:command line arguments、python scripts。

关键思想

  • 函数是组织、复用和测试代码的基本单位。
  • return 用于明确给出函数结果。
  • 文档字符串让函数具备内置说明。
  • Python 标准库提供大量现成工具,应该优先使用。
  • 异常是 Python 中报告和处理错误的主要机制。
  • try-except 可以让程序在遇到坏数据时继续运行。
  • raise 可以主动报告程序中的异常状态。
  • 将脚本逻辑封装为函数后,可以更方便地交互测试。
  • 使用 csv 模块比手动拆分 CSV 文本更可靠。
  • 使用 sys.argv 可以让脚本接收命令行参数,减少硬编码。

与前后内容的关系

本文承接 summaries/06_Files 中的文件读取和投资组合成本计算示例,将其进一步封装为函数,并加入错误处理、标准库解析和命令行参数。它也为后续“处理数据”部分打下基础,尤其是围绕 CSV 文件、异常数据、可复用程序结构等主题。