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