前言:本博文主要讲解Python函数的用法,属于Python高级语法。
一. 函数的作用
二. 函数的使用步骤
1. 定义函数
2. 调用函数
三. 函数的参数作用
四. 函数的返回值作用
五. 函数的说明文档
1. 语法
2. 快速体验
六. 函数嵌套调用
七. 函数应用
1. 打印图形
2. 函数计算
八. 变量作用域
九. 多函数程序执行流程
十. 函数的返回值
十一. 函数的参数
1. 位置参数
2. 关键字参数
3. 缺省参数
4. 不定长参数
十二. 拆包和交换变量值
1. 拆包
2. 交换变量值
十三. 引用
1. 了解引用
2. 引用当做实参
十四. 可变和不可变类型
十五. 总结
函数就是将一段具有独立功能的代码块 整合到一个整体并命名,在需要的位置调用这个名称即可完成对应的需求。
函数在开发过程中,可以更高效的实现代码重用。
def 函数名(参数): 代码1 代码2 ......
1
2
3
4
函数名(参数)1
注意:
不同的需求,参数可有可无。
在Python中,函数必须先定义后使用。
一定是先定义函数,后调用函数。
思考:完成需求如下:一个函数完成两个数1和2的加法运算,如何书写程序?
# 定义函数def add_num1(): result = 1 + 2 print(result)# 调用函数add_num1()
1
2
3
4
5
6
7
8
思考:上述add_num1函数只能完成数字1和2的加法运算,如果想要这个函数变得更灵活,可以计算任何用户指定的两个数字的和,如何书写程序?
分析:用户要在调用函数的时候指定具体数字,那么在定义函数的时候就需要接收用户指定的数字。函数调用时候指定的数字和定义函数时候接收的数字即是函数的参数。
# 定义函数时同时定义了接收用户数据的参数a和b,a和b是形参def add_num2(a, b): result = a + b print(result)# 调用函数时传入了真实的数据10 和 20,真实数据为实参add_num2(10, 20)12345678
函数的参数:函数调用的时候可以传入真实数据,增大函数的使用的灵活性。
形参:函数定义时书写的参数(非真实数据)
实参:函数调用时书写的参数(真实数据)
例如:我们去超市购物,比如买烟,给钱之后,是不是售货员会返回给我们烟这个商品,在函数中,如果需要返回结果给用户需要使用函数返回值。
def buy(): return '烟'# 使用变量保存函数返回值goods = buy()print(goods)
1
2
3
4
5
6
需求:制作一个计算器,计算任意两数字之和,并保存结果。
def sum_num(a, b): return a + b# 用result变量保存函数返回值result = sum_num(1, 2)print(result)1234567
函数的返回值
作用:函数调用后,返回需要的计算结果
写法
return 表达式
1
思考:定义一个函数后,程序员如何书写程序能够快速提示这个函数的作用?
答:注释
思考:如果代码多,我们是不是需要在很多代码中找到这个函数定义的位置才能看到注释?如果想更方便的查看函数的作用怎么办?
答:函数的说明文档
函数的说明文档也叫函数的文档说明。
定义函数的说明文档
def 函数名(参数): ''' 说明文档的位置 ''' 代码 ......1234
查看函数的说明文档
help(函数名)
1
def sum_num(a, b): ''' 求和函数 ''' return a + bhelp(sum_num)123456
作用:保存函数解释说明的信息
写法
def 函数名(): ''' 函数说明文档 '''
1
2
所谓函数嵌套调用指的是一个函数里面又调用了另外一个函数。
示例
def testB(): print('---- testB start----') print('这里是testB函数执行的代码...(省略)...') print('---- testB end----')def testA(): print('---- testA start----') testB() print('---- testA end----')testA()1234567891011
效果
执行流程
如果函数A中,调用了另外一个函数B,那么先把函数B中的任务都执行完毕之后才会回到上次 函数A执行的位置。
打印一条横线
def print_line(): print('-' * 20)print_line()
1
2
3
4
5
打印多条横线
def print_line(): print('-' * 20)def print_lines(num): i = 0 while i < num: print_line() i += 1print_lines(5)123456789101112
求三个数之和
def sum_num(a, b, c): return a + b + cresult = sum_num(1, 2, 3)print(result) # 6
1
2
3
4
5
6
求三个数平均值
def average_num(a, b, c): sumResult = sum_num(a, b, c) return sumResult / 3result = average_num(1, 2, 3)print(result) # 2.0123456
变量作用域指的是变量生效的范围,主要分为两类:局部变量和全局变量。
局部变量
所谓局部变量是定义在函数体内部的变量,即只在函数体内部生效。
def testA(): a = 100 print(a)testA() # 100print(a) # 报错:name 'a' is not defined
1
2
3
4
5
6
7
8
变量a是定义在
testA
函数内部的变量,在函数外部访问则立即报错。
局部变量的作用:在函数体内部,临时保存数据,即当函数调用完成后,则销毁局部变量。
全局变量:指的是在函数体内、外都能生效的变量。
思考:如果有一个数据,在函数A和函数B中都要使用,该怎么办?
答:将这个数据存储在一个全局变量里面。
# 定义全局变量aa = 100def testA(): print(a) # 访问全局变量a,并打印变量a存储的数据def testB(): print(a) # 访问全局变量a,并打印变量a存储的数据testA() # 100testB() # 1001234567891011121314
思考:testB
函数需求修改变量a的值为200,如何修改程序?
a = 100def testA(): print(a)def testB(): a = 200 print(a)testA() # 100testB() # 200print(f'全局变量a = {a}') # 全局变量a = 100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
思考:在testB
函数内部的a = 200
中的变量a是在修改全局变量a
吗?
答:不是。观察上述代码发现,15行得到a的数据是100,仍然是定义全局变量a时候的值,而没有返回
testB
函数内部的200。综上:testB
函数内部的a = 200
是定义了一个局部变量。
思考:如何在函数体内部修改全局变量?
a = 100def testA(): print(a)def testB(): # global 关键字声明a是全局变量 global a a = 200 print(a)testA() # 100testB() # 200print(f'全局变量a = {a}') # 全局变量a = 2001234567891011121314151617
一般在实际开发过程中,一个程序往往由多个函数(后面知识中会讲解类)组成,并且多个函数共享某些数据,如下所示:
共用全局变量
# 1. 定义全局变量glo_num = 0def test1(): global glo_num # 修改全局变量 glo_num = 100def test2(): # 调用test1函数中修改后的全局变量 print(glo_num) # 2. 调用test1函数,执行函数内部代码:声明和修改全局变量test1()# 3. 调用test2函数,执行函数内部代码:打印test2() # 100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
返回值作为参数传递
def test1(): return 50def test2(num): print(num)# 1. 保存函数test1的返回值result = test1()# 2.将函数返回值所在变量作为参数传递到test2函数test2(result) # 501234567891011121314
思考:如果一个函数如些两个return (如下所示),程序如何执行?
def return_num(): return 1 return 2result = return_num()print(result) # 1
1
2
3
4
5
6
7
答:只执行了第一个return,原因是因为return可以退出当前函数,导致return下方的代码不执行。
思考:如果一个函数要有多个返回值,该如何书写代码?
def return_num(): return 1, 2result = return_num()print(result) # (1, 2)123456
注意:
return a, b
写法,返回多个数据的时候,默认是元组类型。return后面可以连接列表、元组或字典,以返回多个值。
位置参数:调用函数时根据函数定义的参数位置来传递参数。
def user_info(name, age, gender): print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')user_info('TOM', 20, '男')
1
2
3
4
5
注意:传递和定义参数的顺序及个数必须一致。
函数调用,通过“键=值”形式加以指定。可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求。
def user_info(name, age, gender): print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')user_info('Rose', age=20, gender='女')user_info('小明', gender='男', age=16)123456
注意:函数调用时,如果有位置参数时,位置参数必须在关键字参数的前面,但关键字参数之间不存在先后顺序。
缺省参数也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值(注意:所有位置参数必须出现在默认参数前,包括函数定义和调用)。
def user_info(name, age, gender='男'): print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')user_info('TOM', 20)user_info('Rose', 18, '女')
1
2
3
4
5
6
注意:函数调用时,如果为缺省参数传值则修改默认参数值;否则使用这个默认值。
不定长参数也叫可变参数。用于不确定调用的时候会传递多少个参数(不传参也可以)的场景。此时,可用包裹(packing)位置参数,或者包裹关键字参数,来进行参数传递,会显得非常方便。
包裹位置传递
def user_info(*args): print(args)# ('TOM',)user_info('TOM')# ('TOM', 18)user_info('TOM', 18)12345678
注意:传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组(tuple),args是元组类型,这就是包裹位置传递。
包裹关键字传递
def user_info(**kwargs): print(kwargs)# {'name': 'TOM', 'age': 18, 'id': 110}user_info(name='TOM', age=18, id=110)
1
2
3
4
5
6
综上:无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程。
拆包:元组
def return_num(): return 100, 200num1, num2 = return_num()print(num1) # 100print(num2) # 2001234567
拆包:字典
dict1 = {'name': 'TOM', 'age': 18}a, b = dict1# 对字典进行拆包,取出来的是字典的keyprint(a) # nameprint(b) # ageprint(dict1[a]) # TOMprint(dict1[b]) # 18
1
2
3
4
5
6
7
8
9
需求:有变量a = 10
和b = 20
,交换两个变量的值。
方法一
借助第三变量存储数据。
# 1. 定义中间变量c = 0# 2. 将a的数据存储到cc = a# 3. 将b的数据20赋值到a,此时a = 20a = b# 4. 将之前c的数据10赋值到b,此时b = 10b = cprint(a) # 20print(b) # 101234567891011121314
方法二
a, b = 1, 2a, b = b, aprint(a) # 2print(b) # 1
1
2
3
4
在python中,值是靠引用来传递来的。
我们可以用id()
来判断两个变量是否为同一个值的引用。 我们可以将id值理解为那块内存的地址标识。
# 1. int类型a = 1b = aprint(b) # 1print(id(a)) # 140708464157520print(id(b)) # 140708464157520a = 2print(b) # 1,说明int类型为不可变类型 print(id(a)) # 140708464157552,此时得到是的数据2的内存地址print(id(b)) # 140708464157520# 2. 列表aa = [10, 20]bb = aaprint(id(aa)) # 2325297783432print(id(bb)) # 2325297783432aa.append(30)print(bb) # [10, 20, 30], 列表为可变类型print(id(aa)) # 2325297783432print(id(bb)) # 23252977834321234567891011121314151617181920212223242526272829
代码如下:
def test1(a): print(a) print(id(a)) a += a print(a) print(id(a))# int:计算前后id值不同b = 100test1(b)# 列表:计算前后id值相同c = [11, 22]test1(c)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
所谓可变类型与不可变类型是指:数据能够直接进行修改,如果能直接修改那么就是可变,否则是不可变。
可变类型
列表
字典
集合
不可变类型
整型
浮点型
布尔
字符串
元组
变量作用域
全局:函数体内外都能生效
局部:当前函数体内部生效
函数多返回值写法
return 表达式1, 表达式2...1
函数的参数
收集所有关键字参数,返回一个字典
收集所有位置参数,返回一个元组
缺省参数就是默认参数
写法:key=vlaue
写法: key=value
特点:形参和实参的书写顺序可以不一致;关键字参数必须书写在位置参数的后面
形参和实参的个数和书写顺序必须一致
位置参数
关键字参数
缺省参数
不定长位置参数
不定长关键字参数
引用:Python中,数据的传递都是通过引用。
联系客服