第8章 函数
系列第 8 篇:本文是《Python编程 从入门到实践》读书笔记系列的第 8 篇。
本文内容:函数定义、位置实参与关键字实参、默认值、返回值、传递列表、任意数量实参、函数存储在模块中。
本章目标:定义和调用函数,传递参数的各种方式,返回值,将函数存储在模块中。
开篇:这篇解决什么问题
函数不是为了让代码看起来高级,而是为了把一段有明确目的的逻辑收起来,需要时再调用。写脚本时,只要某段逻辑出现第二次,就可以考虑封装成函数。
本篇你会学到什么
- 如何定义和调用函数
- 位置参数、关键字参数、默认参数怎么用
- 函数如何返回值
- 列表传给函数时要注意什么
- 如何把函数放进模块里复用
场景案例:封装一条任务通知
不使用函数时,代码可能这样写:
python
task_name = 'daily_report'
owner = 'alice'
print('Task ' + task_name + ' is assigned to ' + owner + '.')
如果很多地方都要输出类似通知,就可以封装成函数:
python
def notify_task(task_name, owner):
"""Print a simple task notification."""
print('Task ' + task_name + ' is assigned to ' + owner + '.')
notify_task('daily_report', 'alice')
notify_task('data_backup', 'bob')
函数让重复逻辑有了名字,也让代码更容易复用。
知识点拆解
1. 定义函数
python
def greet_user():
"""Display a simple greeting."""
print("Hello!")
greet_user()
def 用来定义函数,缩进里的代码是函数体。函数定义后,不会自动执行,必须调用才会运行。
2. 向函数传递信息
python
def greet_user(username):
"""Display a greeting to the user."""
print("Hello, " + username.title() + "!")
greet_user('alice')
username 是形参,'alice' 是实参。
3. 位置实参
位置实参按顺序匹配:
python
def describe_task(task_name, owner):
print(task_name + ' -> ' + owner)
describe_task('daily_report', 'alice')
如果顺序写反,结果也会跟着变错。所以位置参数适合数量少、顺序很清楚的情况。
4. 关键字实参
关键字实参直接写参数名:
python
def describe_task(task_name, owner):
print(task_name + ' -> ' + owner)
describe_task(owner='alice', task_name='daily_report')
这种写法顺序不重要,可读性更强。
5. 默认参数
python
def describe_task(task_name, status='pending'):
print(task_name + ' is ' + status)
describe_task('daily_report')
describe_task('data_backup', 'done')
默认参数要放在没有默认值的参数后面。
6. 返回值
函数可以用 return 返回结果:
python
def build_task_name(project, task):
full_name = project + '-' + task
return full_name.lower()
name = build_task_name('WorkBuddy', 'Report')
print(name)
输出:
text
workbuddy-report
7. 返回字典
python
def build_task(task_name, owner, status='pending'):
task = {
'name': task_name,
'owner': owner,
'status': status,
}
return task
new_task = build_task('daily_report', 'alice')
print(new_task)
函数返回字典很常见,适合封装结构化数据。
8. 传递列表
python
def print_tasks(tasks):
for task in tasks:
print('- ' + task)
todo_tasks = ['write report', 'check email']
print_tasks(todo_tasks)
9. 函数中修改列表
列表传给函数后,函数内部可以修改它:
python
def finish_tasks(pending_tasks, finished_tasks):
while pending_tasks:
task = pending_tasks.pop()
finished_tasks.append(task)
pending = ['write report', 'check email']
finished = []
finish_tasks(pending, finished)
print(pending)
print(finished)
如果不希望修改原列表,可以传副本:
python
finish_tasks(pending[:], finished)
10. 任意数量的位置实参
python
def make_tags(*tags):
for tag in tags:
print('#' + tag)
make_tags('python', 'note', 'beginner')
*tags 会把多个位置实参收集成元组。
11. 任意数量的关键字实参
python
def build_profile(username, **info):
profile = {'username': username}
for key, value in info.items():
profile[key] = value
return profile
profile = build_profile('alice', role='admin', location='beijing')
print(profile)
**info 会把关键字实参收集成字典。
12. 导入模块
可以把函数放到单独文件里,比如 task_utils.py:
python
def notify_task(task_name, owner):
print('Task ' + task_name + ' is assigned to ' + owner + '.')
在另一个文件中导入:
python
from task_utils import notify_task
notify_task('daily_report', 'alice')
不建议为了省事到处使用 from module import *。明确导入需要的函数,可读性更好。
初学者容易踩的坑
| 问题 | 常见原因 | 建议 |
|---|---|---|
| 函数定义了但没执行 | 忘记调用 | 定义后写 function_name() |
| 参数顺序传错 | 位置实参依赖顺序 | 参数多时用关键字实参 |
| 默认参数位置错误 | 默认参数放在普通参数前面 | 默认参数放最后 |
函数返回 None |
忘记写 return |
需要结果时必须 return |
| 函数修改了原列表 | 传入的是同一个列表对象 | 不想修改时传副本 list[:] |
工作里能怎么用
| 场景 | 函数可以怎么用 |
|---|---|
| 读取配置 | load_config() |
| 保存结果 | save_result() |
| 发送通知 | notify_task() |
| 校验输入 | validate_input() |
| 处理列表 | filter_tasks() |
示例:判断任务是否可以执行:
python
def can_run(task):
return task.get('status') == 'pending'
task = {'name': 'daily_report', 'status': 'pending'}
if can_run(task):
print('Run task.')
小结
- 函数用
def定义,用函数名加括号调用 - 位置实参按顺序匹配
- 关键字实参按名称匹配,可读性更强
- 默认参数适合给常用值设置默认行为
return用来返回结果- 函数可以接收列表,也可能修改列表
*args接收任意数量位置实参**kwargs接收任意数量关键字实参- 模块化能让函数跨文件复用
下一篇
下一篇继续讲类。函数能整理动作,类可以把数据和动作放在一起,更适合表达任务、用户、订单这类对象。