内容正文:
第6章 函数与模块
1
学习目标/Target
了解函数,能够说出函数的概念以及好处
掌握函数的定义与调用,能够正确地定义并调用函数
掌握函数参数的传递方式,能够通过多种方式给函数的参数传递数据
掌握函数的返回值,能够根据需要使用return语句返回函数处理结果
掌握变量作用域,能够说出全局变量和局部变量的特点
2
学习目标/Target
掌握递归函数的使用,能够运用递归函数解决阶乘的问题
掌握匿名函数的使用,能够运用匿名函数简化简单函数的定义
掌握模块的导入与使用,能够通过不同语句导入模块并使用模块的内容
掌握模块的变量,能够归纳变量__all__和__name__的作用
3
章节概述/ Summary
程序开发过程中,随着需要处理的问题变得越来越难,程序也会变得越来越长。冗长的程序牵扯的情况比较复杂,这不仅增加了阅读和理解的难度,也不利于后期对程序的维护与二次开发。函数和模块的出现便解决这些问题,它们为开发人员提供了丰富的工具和自由度,使得开发各种复杂的程序变得更加简单和高效。本章将详细介绍函数的相关知识,并简要介绍一些关于模块的知识。
4
目录/Contents
01
函数概述
函数的基础知识
函数的参数传递
02
03
函数的返回值
04
5
目录/Contents
05
变量作用域
实例:智能聊天机器人
函数的特殊形式
06
07
模块
08
6
函数的参数传递
6.3
7
6.3.1 位置传递
当调用函数时,默认情况下实参会按照位置顺序传递给对应的形参,即将第一个实参传递给第一个形参,第二个实参传递给第二个形参,以此类推。
def test_param(a, b, c):
print(a, b, c)
test_param(1, 2, 3)
8
6.3.2 关键字传递
虽然位置传递的方式比较便捷,但是如果形参的数目过多,开发者很难记住每个形参的作用,这时可以通过关键字传递的方式给形参传值,这里的关键字就是形参的名称。当调用函数时,通过“形参名=实参”的形式将形参与实参关联,按照形参的名称进行参数传递,它允许实参和形参的顺序不一致。
def test_param(a, b, c):
print(a, b, c)
test_param(a=1, c=3, b=2)
9
多学一招:仅限位置和权限关键字
仅限位置,顾名思义就是调用函数时只能根据位置将实参传递给形参,不能再根据关键字将实参传递给形参。当定义函数时,只要在函数的形参前面明确使用符号/,那么/前面的形参需要严格遵守仅限位置的要求。
def test_param(a, b, /, c): # 定义函数,部分参数遵守仅限位置的要求
print(a, b, c)
test_param(1, 2, 3)
test_param(1, 2, c=3)
1. 仅限位置
10
多学一招:仅限位置和权限关键字
仅限关键字,顾名思义就是调用函数时只能根据关键字将实参传递给形参,不能再根据位置将实参传递给形参。当定义函数时,只要在函数的形参前面明确使用符号*,那么符号*后面的形参需要严格遵守仅限关键字的要求。
2. 仅限关键字
def test_param(a, *, b, c): # 定义函数,部分参数遵守仅限关键字的要求
print(a, b, c)
test_param(1, b=2, c=3)
test_param(a=1, b=2, c=3)
11
6.3.3 默认值传递
在定义函数时可以给每个形参指定默认值,基本形式为“形参名=默认值”,这样在调用时既可以给带有默认值的形参传递实参,以便重新为该形参赋值,也可以省略相应的实参,使用形参的默认值。
def test_param(a, b, c=6
print(a, b, c)
test_param(1, 2, 3)
test_param(1, 2)
12
6.3.4 包裹传递
若函数在定义时无法确定接收多少个实参,那么可以在定义函数时给形参名称添加“*”或“**”。
若一个形参名称前面加上“*”,它可以接收一个以元组形式包裹的多个实参。
若一个形参名称前面加上“**”,它可以接收一个以字典形式包裹的多个实参。
例如,定义一个形参为*args的函数,代码如下
def test_param(*args): # 定义函数,该函数有一个加*的形参
print(args)
调用以上定义的test_param()函数可以传入多个实参,比如传入5个实参,代码如下:
test_param(1, 2, 3, 4, 5)
13
6.3.4 包裹传递
例如,定义一个形参为**kwargs的函数,代码如下:
def test_param(**kwargs): # 定义函数,该函数有一个加**的形参
print(kwargs)
调用以上定义的test_param()函数时可以传入多个实参,比如传入5个实参,代码如下:
test_param(a=1, b=2, c=3, d=4, e=5)
14
6.3.5 解包裹传递
在调用函数时,若函数接收的实参为元组或字典类型,可以使用“*”和“**”对实参解包裹,将实参拆分为多个值,并按照位置传递或关键字传递的方式将实参赋给形参。
def test_param(a, b, c):
print(a, b, c)
tuple_demo = (1, 2, 3)
test_param(*tuple_demo) # 调用函数,使用*对实参解包裹
15
6.3.5 解包裹传递
下面再来看一下对字典解包裹的示例,代码如下:
dict_demo = {'a': 1, 'b': 2, 'c': 3}
test_param(**dict_demo) # 调用函数,使用**对实参解包裹
16
6.3.6 混合传递
前面介绍的几种参数传递的方式可以混合使用,但是在定义函数或调用函数时需要注意前后的顺序。在定义函数时,带默认值的形参必须位于普通形参(不带默认值或标识的形参)之后,带“**”标识的形参必须位于带“*”标识的形参之后。
17
6.3.6 混合传递
当调用具有以上几种形参的函数时,需要遵循一定的规则:
优先按照位置传递;
其次按照关键字传递;
再次按照默认值传递;
最后按照包裹传递。
18
6.3.6 混合传递
例如,定义一个函数,该函数包含多种形式的形参,具体代码如下:
def test_param(a, b, c=33, *args, **kwargs):
print(a, b, c, args, kwargs)
调用test_param()函数时,依次传入不同个数和形式的实参,具体代码如下:
test_param(1, 2)
test_param(1, 2, c=3)
test_param(1, 2, 3, 'a', 'b')
test_param(1, 2, 3, 'a', 'b', x=99)
19
$$