函数的定义与使用
- 函数的定义:
将一件事情的步骤封装在一起并得到最终的结果。函数名代表了这个函数要做的事情,函数体是实现函数功能的流程。
实现一个函数也称为实现一个方法或功能。函数可以帮助实现功能复用,通过函数名可以知道函数的作用。
函数的作用及好处:
1. 减少重复代码
2. 方便修改,更易于扩展
3. 保持代码一致性
- 函数的分类:
python 中的函数分为内置函数和自定义函数。内置函数是 python 自带的函数,不需要定义或者导入即可使用,而自定义函数是用户自己定义的函数,不定义无法使用。
- 函数的创建:
通过关键字 def
来实现 python 中函数的创建。
用法:
def 函数名(函数参数):
函数具体实现代码块
return 返回值
示例:
>>> def say_hello(name):
... print('Hello, {}'.format(name))
...
>>> say_hello('xiaobai')
Hello, xiaobai
>>> say_hello('xiaohei')
Hello, xiaohei
- 函数的返回:
通过关键字 return
来实现 python 中函数的返回。只有函数才具有返回值,因此 return
只能在函数体内使用。
return
支持返回所有的 python 类型,有返回值的函数可以直接复制给一个变量,默认的返回值是 None
。示例:
>>> def add(a, b):
... c = a + b
... return c
...
>>> sum = add(5, 10)
>>> sum
15
return
代表一个函数执行的结束,直接将结果返回,函数体内 return
下面的代码不会被执行。
return
与 print
的区别:
print 只是单纯的将对象打印,不支持赋值语句
return 是对函数执行结果的返回,支持赋值语句
函数可以返回多个返回值,以元组的形式返回。
- 形参与实参
函数参数的作用是传递数据给函数使用。在使用的过程中,参数有两种形式:形式参数(形参)和实际参数(实参)。
形参:定义函数时的参数;实参:调用函数时的参数。实参又分为位置参数与关键字参数。
位置参数,即调用函数时必须要传的参数,位置参数的顺序与定义的形参一一对应;关键字参数是调用函数时传递给函数的键值对,关键字参数无需考虑函数调用中的实参顺序,还清楚地指出了函数调用中各个值的用途。
- 位置参数:
在定义函数的时候,没有默认值且必须在函数执行的时候传入的参数,且传入顺序与参数顺序相同,这就是必传参数,也称为位置参数。
必传参数,在定义函数的时候,参数后边没有等号与默认值。函数中定义的参数没有默认值,在调用函数时如果不传入则报错。
调用函数时,根据函数定义的参数位置来传递参数,传递的参数必须与函数定义的参数两者一一对应,如果 “传递的参数个数” 不等于 “函数定义的参数个数”,运行时会报错。示例:
>>> def add(a, b):
... c = a + b
... return c
...
>>> sum = add(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add() missing 1 required positional argument: 'b'
- 默认参数:
在定义函数的时候,定义的参数含有默认值,通过赋值语句给一个默认的值,这就是默认参数,也称为非必传参数。
如果默认参数在调用函数的时候赋予了新的值,函数将优先使用新传入的值进行工作。示例:
>>> def add(a=2, b=5):
... c = a + b
... return c
...
>>> add()
7
>>> add(6)
11
>>> add(9, 10)
19
带有默认值的参数必须放在参数列表末尾,否则函数会报错。
- 可变位置参数:
可变参数分为可变位置参数和可变关键字参数,可变参数也称为不确定参数。
在函数定义中,可以将函数设定为可以接受任意数量的参数,函数调用时就可以传递任意数量的参数,这就是可变位置参数。在参数前加上符号 *
表示函数可以接受可变数量的参数。
用法:
def 函数名(*args):
函数具体实现代码块
return 返回值
调用带可变位置参数的函数时,所有的参数被合并成一个元组,合并后的元组被赋值给 args
,通过遍历 args
可以访问传入的参数。示例:
>>> def add(*params):
... c = 0
... for arg in params:
... c += arg
... return c
...
>>> add(1)
1
>>> add(7, 8, 9, 10)
34
>>> add(2, 4, 4, 6, 238, 3125)
3379
- 可变关键字参数:
可变参数分为可变位置参数和可变关键字参数,可变参数也称为不确定参数。
调用函数时,以 “参数名 = 参数值” 的形式传递参数。在函数定义中,在参数前加上符号 **
表示函数可以接收可变关键字参数。
用法:
def 函数名(**kwargs):
函数具体实现代码块
return 返回值
调用带可变关键字参数的函数时,所有的参数被合并成一个字典,合并后的字典被赋值给 kwargs
,通过访问 kwargs
可以访问参数名和参数值。示例:
>>> def person_info(**param):
... for k, v in param.items():
... print(k, ':', v)
...
>>> person_info(name='xiaobai', age=18, height=180)
name : xiaobai
age : 18
height : 180
>>> def person_info(**param):
... for k, v in param.items():
... print(k, ':', v)
...
>>> person = {
'name': 'xiaobai', 'age': 18, 'height': 180}
>>> person_info(**person)
name : xiaobai
age : 18
height : 180
位置参数、默认参数、可变位置参数、可变关键字参数,可以全部存在于一个函数内,一个函数也可以有 0 个或多个参数。
python 中参数的定义从左到右依次是位置参数、默认参数、可变位置参数、可变关键字参数,传参顺序也应该与定义顺序一致。如果参数顺序不一致,建议对参数进行赋值,防止引用函数时报错。
- 参数定义类型:
python3.7之后,可以在定义函数的同时,为参数指定类型。只不过指定类型只是为了说明,函数在实际执行时不会检查参数类型,参数类型不符时也并不会报错。
用法:
# 参数1为字符串类型,参数2为整型
def 函数名(参数1:str, 参数2:int=具体整数):
函数具体实现代码块
return 返回值
示例:
>>> def person_info(name:str, age:int=18, height:int=180):
... print('the person\'s name is {}, his age is {}, and his height is {}'.format(name, age, height))
...
>>> person_info('xiaobai', '18', '180')
the person's name is xiaobai, his age is 18, and his height is 180
>>> xiaobai = ('xiaobai', '20', '175')
>>> person_info(*xiaobai)
the person's name is xiaobai, his age is 20, and his height is 175
- 全局变量和局部变量:
变量的作用域,即变量的作用范围,一个变量如果超出了它的作用范围则该变量会失效。
由变量的作用域可以将变量分为全局变量与局部变量。
在全局环境下定义的变量称为全局变量,全局变量的作用域是全局,即可以在全局起作用。在函数体内部定义的变量称为局部变量,局部变量的作用域只有函数内部,只能在函数内部起作用。
函数内部可以引用全局变量,而在函数外部不能引用函数的局部变量。当全局变量与局部变量的变量名相同时,在函数内部优先调用局部变量。示例:
>>> name = 'xiaobai'
>>> def info():
... name = 'xiaohei'
... print('函数体内', name)
...
>>> info()
函数体内 xiaohei
>>> print('函数体外', name)
函数体外 xiaobai
global
关键字:
全局变量可以作用于整个程序,只不过需要 import
来导入对应全局变量的模块。另外,全局变量很容易被局部变量覆盖,因为将全局变量更改为局部变量只需要将变量在函数内重新赋值即可。
而要想将函数内的局部变量改为全局变量,则要通过 global
关键字声明,这样就可以在函数外部来引用该局部变量。示例:
>>> name = 'xiaobai'
>>> def info():
... global age
... name = 'xiaohei'
... age = 18
... print('函数体内', name, age)
...
>>> info()
函数体内 xiaohei 18
>>> print('函数体外', name, age)
函数体外 xiaobai 18
需要注意的是,global
应该在变量赋值之前声明为全局变量,否则不会生效。此外,global
仅支持字符串、数字(整型、浮点型)、空类型和布尔类型的变量的全局声明,而列表、字典的变量不需要 global
声明也可以引用。
- 递归函数:
一个函数最终的返回结果是自己本身这个函数,那这个函数就称为递归函数。递归函数相当于不停地将自己反复执行,因此必须要有一个明确的结束条件,否则会进入死循环。
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
用法:
def 函数名(参数):
函数具体实现代码块
return 函数名(参数)
示例:
count = 0
def test():
global count
count += 1
if count != 5:
print('count 值不等于 5,重新执行自己,当前 count 值是 %s' % count)
return test()
else:
print('count 值等于 5,退出函数')
test()
结果:
count 值不等于 5,重新执行自己,当前 count 值是 1
count 值不等于 5,重新执行自己,当前 count 值是 2
count 值不等于 5,重新执行自己,当前 count 值是 3
count 值不等于 5,重新执行自己,当前 count 值是 4
count 值等于 5,退出函数
使用递归函数需要注意:
不要无限递归,要防止内存溢出
避免滥用递归,提前准备好退出方案
能使用 while 就不要用递归
- 匿名函数
lambda
:
顾名思义,匿名函数就是不需要显式地定义函数名的函数,通过关键字 lambda
定义。lambda
后面跟的只能是表达式,不能是赋值语句或代码块。
用法:
lambda parameter_list: expression
匿名函数有个限制,就是只能有一个表达式,不用写 return
,返回值就是该表达式的结果。
匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数。
示例:
def add(x, y):
return x + y
print(add(2, 3))
f = lambda x, y: x + y #匿名函数赋值给变量f
print(f(2, 3))
5 #结果
5