#### 1. 函数的作用
1. 对代码进行封装
2. 代码复用
#### 2. 函数的定义与调用
```
def 函数名(参数):
代码逻辑
[return 返回值]
```
> 注意:
1.根据具体情况,参数和返回值可有可无
2. 函数必须先定义后使用
```
# 函数的调用
函数名(参数) # 参数可选的根据实际情况
```
#### 3. 函数的说明文档
自己定义了一个函数后,为了方便别人知道函数的作用,可以添加解释性的文字说明。
```
def add_three_num(a, b, c):
"""求三个数的和"""
return a+b+c
help(add_three_num) # 可以查看函数的说明
```
#### 4. 函数的变量
##### 4.1 变量的作用域
变量的作用域指的是变量的生效范围,主要分为两类:局部变量和全局变量。
- 局部变量
局部变量是指指定义在函数体内部的变量,即只在函数体内部生效。
```
def test1():
num = 33
print(num)
test1() # 100
print(num) # 报错
```
注意: 局部变量的作用是定义在函数内部的变量,用于临时保存数据。在函数调用完成后,立即销毁。
- 全局变量
全局变量是指定义在函数外面,在函数的内部和外面都能生效的变量。
```
num = 100
def test2():
print(f'函数内:{num}')
test2()
num+=100
print(f'函数外:{num}')
```
- 在函数内部修改全局变量
在函数内部修改全局变量需要使用global关键字
```
num = 100
def test2():
global num
num+=100
print(f'函数内:{num}')
test2()
num+=100
print(f'函数外:{num}')
```
#### 5. 函数的返回值
python中函数的返回值通常和其他语言没什么区别,需要注意的是多个返回值的情况。
```
# 1. 返回多个值,默认情况
def test():
return 1,2,3
res = test()
print(res) # (1,2,3),返回多个值默认封装成元组返回
# 2. 返回多个值,手动组合,可以组合成字典、列表、元组
def test():
return [1,2,3]
res = test()
print(res)
```
#### 6. 函数的参数
- 形参: 函数定义时预先定义的参数
- 实参: 函数调用时实际传递进来的参数
##### 6.1 位置参数
位置参数:调用函数时根据函数定义的参数位置来传递参数。
``` python
def user_info(name, age, gender):
print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')
user_info('TOM', 20, '男')
```
> 注意:传递和定义参数的顺序及个数必须一致。
##### 6.2 关键字参数
函数调用,通过“键=值”形式加以指定。可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求。
``` python
def user_info(name, age, gender):
print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')
user_info('Rose', age=20, gender='女')
user_info('小明', gender='男', age=16)
```
注意:**函数调用时,如果有位置参数时,位置参数必须在关键字参数的前面,但关键字参数之间不存在先后顺序。**
##### 6.3 缺省参数
缺省参数也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值(注意:所有位置参数必须出现在默认参数前,包括函数定义和调用)。
``` python
def user_info(name, age, gender='男'):
print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')
user_info('TOM', 20)
user_info('Rose', 18, '女')
```
> 注意:函数调用时,如果为缺省参数传值则修改默认参数值;否则使用这个默认值。
##### 6.4 不定长参数
不定长参数也叫可变参数。用于不确定调用的时候会传递多少个参数(不传参也可以)的场景。此时,可用包裹(packing)位置参数,或者包裹关键字参数,来进行参数传递,会显得非常方便。
- 包裹位置传递
``` python
def user_info(*args):
print(args)
# ('TOM',)
user_info('TOM')
# ('TOM', 18)
user_info('TOM', 18)
```
> 注意:传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组(tuple),args是元组类型,这就是包裹位置传递。
- 包裹关键字传递
``` python
def user_info(**kwargs):
print(kwargs)
# {'name': 'TOM', 'age': 18, 'id': 110}
user_info(name='TOM', age=18, id=110)
```
> 综上:无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程。
##### 6.7 补充: 解包
```
a, b, c = (1,2,3) # 元组解包
a, b, c = [1,2,3] # 列表解包
mydict = {1:1,2:2,3:3}
mydict[1] # 字典解包
```
即: 组包可以理解为把单个元素装进容器,解包就是把元素从容器中拿出来。
#### 7. lambda表达式
lambda函数也称为匿名函数,主要是应对于某些函数只有一个返回值,并且就一句话,使用lambda可以简化它的编写。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
lambda语法: lambda 参数列表: 表达式
```
# 平方
f = lambda x:x**2
print(f(3))
# 求和
print((lambda x,y: x+y)(3,4))
```
#### 8. 内置高阶函数
把函数作为参数传入到函数中,这样的函数称为高阶函数。python中内置了一些高阶函数,常用的有map()、reduce()、filter()等
这个是后面装饰器的基础之一,特别重要。
##### 8.1 高阶函数初体验
demo: 求两个数的绝对值之和
```
# 方法一:
def add_num(a, b):
return abs(a) + abs(b)
result = add_num(-1, 2)
print(result) # 3
# 方法二:
def sum_num(a, b, f):
return f(a) + f(b)
result = sum_num(-1, 2, abs)
print(result) # 3
```
###### 8.2.1 map()
map(func,list),将传入的函数变量func作用到list中的每个元素上,并将结果组成迭代器返回。
```
f = lambda x:x*x
lst = list(range(5))
result = map(f, lst)
print(result)
print(list(result))
```
###### 8.2.2 reduce()
reduce(func(x,y),lst),其中func必须有两个参数。每次func计算的结果继续和序列的下⼀个元素做累积计算。
```
f = lambda x,y:x+y
lst = list(range(5))
import functools
result = functools.reduce(f,lst)
print(result)
```
###### 8.2.3 filter
filter(func,lst)函数⽤于过滤序列,过滤掉不符合条件的元素, 返回⼀个filter对象。如果要转换为列表,
可以使⽤ list() 来转换。
```
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def func(x):
return x % 2 == 0
result = filter(func, list1)
print(result)
print(list(result))
```