第九章:函数
什么是函数
函数相当于具备某一功能的工具
函数的使用必须遵循:
先定义
后使用
为什么要用函数
-
1、代码的组织结构不清晰,可读性差
2、代码冗余
3、代码可维护性、扩展性差
函数的使用
- 必须遵循先定义后使用的原则
1、函数的基本使用
定义函数时:
- 1、申请内存空间保存函数体代码。
- 2、将函数体申请内存空间的内存地址绑定给func函数名。
- 3、定义函数时不会执行函数体代码,但是会检测函数体的语法。
调用函数时:
- 1、通过func函数名找到函数的内存地址。
- 2、函数名加括号就是触发函数体代码的执行。
def func(): # func = 函数的内存地址
print('来自func函数')
func() # 函数func内存地址加括号就是在调用函数func
def foo():
print('来自foo函数')
func() # 在函数foo中调用func函数
foo()
1、函数定义语法
一个完整的函数定义语法如下:
def 函数名([参数1,参数2...]):
'''函数功能说明''' # 简单的函数可以不用写明
函数体
return 值 # 默认为None
函数名() # 调用函数
2、函数参数的基本使用
函数的参数就相当于函数这个工厂加工一件物品所需要的原材料。
- 在函数定义时,函数名后小括号内的元素,我们统称为参数。通常也被称为形参。
- 同样,在函数调用时,小括号内的元素,也统称为参数。通常被称为实参。
具体介绍如下:
定义函数
1、无参函数
定义函数时小括号内没有参数
def func(): # 定义函数时小括号内没有参数
pass
2、有参函数
定义函数时,函数名后小括号内有参数
def func(a,b):
print(a,b)
func(1,2) # 位置参数形式,调用函数时,必须为函数传值,传值数量必须与定义时一致。
3、空函数
函数体的代码为pass或…
通常应用于函数构思时候暂时占位使用。这里函数有无参数都称为空函数。
def func():
# pass
...
调用函数
调用函数就相当于给函数这个工厂传入原材料。
- 函数调用的本质:就是将值的内存地址传递给函数的形参。所以调用时传入的实参,可以是任意形式,因为它的本质就是内存地址的传递,比如:变量形式、函数对象形式。
1、语句形式
只加括号调用函数
def func():
print('来自func函数')
func()
def add(a, b):
result = a + b
print(result)
add(1, 2)
2、表达式形式
def add(a, b):
result = a + b
print(result)
add(1, 2 * 10)
3、返回值当做参数调用
def add(a, b):
result = a + b
return result
res = add(add(1, 2), 7)
print(res)
函数的返回值
返回值相当于函数这个工厂加工后得到成品。
-
1、函数体内没有return关键字,返回None
-
2、函数只返回一个值:return 值
3、函数返回多个值,用逗号分隔开多个值。会被return以元组形式返回
return关键字是函数 结束的标志,函数体代码一旦运行到return就立即终止函数运行(不管后面有多少代码),并且会将return 后的值当做本次运行的结果返回。
def func(a, b):
result = a * b
return result # 函数只返回一个值
print(a + b) # 这段代码不会运行
res = func(2, 7)
print(res)
# 若代码中有多个返回值时,用逗号分隔开多个值,会被return以元组形式返回
def func():
return 2, 7, [2, 7] # 这里不需要用其他符号来将众多返回值揽括
res = func()
print(res,type(res)) # (2, 7, [2, 7]) <class 'tuple'>
2、函数参数的使用
1、形参与实参
形参
在定义函数阶段,函数名后面的,小括号内的参数被称为形式参数,简称为形参。相当于变量名。
def func(a, b): # 形参a、b,用来接收函数调用时传入的值。
...
实参
在函数调用阶段,函数名后小括号内,传入的值被称为实际参数,简称为实参。相当于变量值。
def func(a, b): # a = 2, b = 7
...
func(2,7) # 实参2, 7
实参传值的三种形式:
- 1、直接以值的形式传值
- 2、以变量形式为其传值
- 3、用函数值为函数传值
def func(a, b):
...
def foo(c, d):
result = c + d
return result
# 1、直接以值的形式传值
func(2, 7)
# 2、实参为形参传值,实际上就是将值的内存地址绑定给形参,所以也可以用变量的形式为其传值。
x = 2
y = 7
func(x, y) # 相当于定义变量时 x = 2;a = x。 y = 7;b = y。
# 3、用函数值为函数传值
func(foo(2,7),7) # 类似于:func(int('2'),7)
形参与实参的关系
-
1、只用在调用阶段才会产生联系。在调用阶段,实参(变量值)会绑定给形参(变量名)。
-
2、这种绑定关系只能是在函数体内使用。
-
3、实参与形参的绑定关系只有在函数调用时生效,函数调用结束后就会解除绑定关系。
2、形参与实参具体使用
1、位置参数
按照从左往右的顺序依次定义的参数称为位置参数。
-
位置形参 :在函数定义阶段,按照从左往右的顺序直接定义的“变量名”。
-
位置实参 :在函数调用阶段,按照从左到右的顺序依次传入的“值”。
-
特点 :函数调用时必须传值,多一个少一个都不行;且按照顺序与形参一一对应。
def func(a,b):
print(a, b)
func(2, 7)
2、关键字参数
-
也称为关键字实参 :在函数调用阶段,按照key=value的形式传入的“值”。
特点:指名道姓的给形参传值,可以不考虑传入的顺序。
def func(a, b):
print(a, b)
func(b=7, a=2)
func(2, 7)
混合使用
- 1、位置实参必须放在关键字实参前
def func(a, b):
print(a, b)
func(2, b=7)
func(b=7, 2) # 语法错误:SyntaxError
- 2、不能为同一个形参重复传值
def func(a, b):
print(a, b)
func(2, 7, b=9) # 类型错误:TypeError
3、默认参数
-
在定义函数阶段,已经被赋值的形参,称为默认参数。也叫默认形参。
特点:在定义阶段就已经被赋值了,也就是说在调用阶段可以不用为其赋值。通常可以用于多个重复传入的值,为其设为默认值,需要时也可以传为需要的值(如:程序猿大多是boy)。
def func(a, b=7):
print(a, b)
func(2)
func(2, 9) # b=7是默认参数,重新为其赋值为9
位置形参与默认形参混用
- 1、位置形参必须在默认形参左边。
- 2、默认参数的值是在函数定义阶段已经被赋值的,也就是被赋予的是值的内存地址。
y = 7
def func(a, b=y): # b->>> 值7的内存地址
print(a, b)
y = 9 # 这里是为全局变量y重新赋值为9
func(2) # 调用func函数,b所绑定的值的内存地址是7的内存地址
# 为形参绑定一个可变容器
# 下述代码会受外界影响,通常不推荐使用
y = []
def func(a, b=y): # b->>> []空列表所指向的内存地址
print(a, b)
y.append('7')
# 这里虽然为列表里面追加了值,但是变量y所指向的内存地址没有改变,
# 形参b所指向的内存地址也没有发生改变。
func(2) # 2 ['7']
3、虽然默认值可以被指定为任意数据类型,但是不推荐使用 可变类型 。
函数最理想的状态:函数的调用只跟函数本身有关系,不受外界代码的影响。使用一个函数通常能够预知得到的结果。
# 相对上一段代码来说,下述代码不受外界代码影响,通常不得已情况下推荐使用
def func(a, b, l=None):