# 函数

## 函数

* [返回顶层目录](https://github.com/luweikxy/machine-learning-notes/tree/7487dd2c1db37d6f5f7b21c48f6cd9b04f21d50b/content/coding/SUMMARY.md#目录)
* [返回上层目录](https://github.com/luweikxy/machine-learning-notes/tree/7487dd2c1db37d6f5f7b21c48f6cd9b04f21d50b/content/coding/python/grammar/python.md)
* [函数定义和类型](https://luweikxy.gitbook.io/machine-learning-notes/python/grammar/pages/-LwEAIUH465KfWjariwD#函数定义和类型)
* [局部变量、全局变量](https://luweikxy.gitbook.io/machine-learning-notes/python/grammar/pages/-LwEAIUH465KfWjariwD#局部变量、全局变量)
* [函数缺省参数、不定长参数、命名参数](https://luweikxy.gitbook.io/machine-learning-notes/python/grammar/pages/-LwEAIUH465KfWjariwD#函数缺省参数、不定长参数、命名参数)
* [递归函数及应用](https://luweikxy.gitbook.io/machine-learning-notes/python/grammar/pages/-LwEAIUH465KfWjariwD#递归函数及应用)
* [匿名函数及应用](https://luweikxy.gitbook.io/machine-learning-notes/python/grammar/pages/-LwEAIUH465KfWjariwD#匿名函数及应用)

## 函数定义和类型

* 对某一功能的封装
* 函数定义

  ```python
  def 函数名称（参数）:
      函数体代码
      return 返回值
  ```

  别忘了定义函数名后面加冒号“:”
* 函数调用：函数名(参数)
* 函数参数

  形参：定义函数时设置的参数

  实参：调用函数时传入的参数

无参函数

```python
def print_user_info():
    print("name:zhangsan")
    print("age:20")

print_user_info()
```

有参函数

```python
def print_user_info2(name, age):
    print("name:{}".format(name))
    print("age:{}".format(age))

name = "zhangsan"
age = 20
print_user_info2(name, age)
```

带有返回值的函数

```python
# 返回单个值
def x_y_sum(x,y):
    res = x + y
    return res
# 返回多个值
def x_y_comp(x,y):
    rs1 = x + y
    rs2 = x - y
    rs3 = x * y
    rs4 = x / y
    # rs = (rs1, rs2, rs3, rs4)
    # return  rs
    return rs1, rs2, rs3, rs4

z = x_y_sum(10, 40)
print(z)
z = x_y_comp(4, 2)
print(z)# (6, 2, 8, 2.0)
print(type(z))# <class 'tuple'>
```

## 局部变量、全局变量

* 局部变量
  * 函数内部定义的变量
  * 不同函数内的局部变量可以定义相同的名字，互不影响
  * 作用范围：函数体内有效，其他函数不能直接使用
* 全局变量
  * 函数外部定义的变量
  * 作用范围：可以在不同函数中使用
  * 在函数内使用global关键字实现修改全局变量的值
  * 全局变量命名建议以g\_开头，如：g\_name

基本操作

```python
# 全局变量
g_name = "zhangsan"
def get_name1():
    print(g_name)

def get_name2():
    print(g_name)

get_name1()
print("--------")
get_name2()
```

想通过在函数内直接修改全局变量的方式是错误的，相当于在函数体内定义了一个与全局变量同名的局部变量。

全局变量不能在函数体内被直接通过赋值而修改。函数体内被修改的那个”全局变量“其实只是函数体内定义的一个局部变量，只是名称相同而已。所以，通过在函数体内直接对全局变量赋值是无法改变其值的。

```python
g_age = 25
def change_age():
    g_age = 35
    print("函数内：",g_age)

change_age()# 函数内： 35
print("--------")
print(g_age)# 25
```

应该在函数体内用global声明全局变量，才能修改：

```python
g_age = 25
def change_age():
    global g_age# 必须使用global关键字声明
    print("修改之前：",g_age)
    g_age = 35
    print("修改之后：",g_age)

change_age()# 修改之前： 25 修改之后： 35
print("--------")
print(g_age)# 35
```

全局变量定义的位置应当放在调用它的函数之前，不然会出错。

原因：python解释器从上到下逐行执行，那当执行此函数时，函数之后的变量是不存在的。

```python
g_num1 = 100
def print_global_num():
    print("g_num1:{}".format(g_num1))
    print("g_num2:{}".format(g_num2))
    print("g_num3:{}".format(g_num3))

g_num2 = 200
print_global_num()
g_num3 = 300# 在调用函数之后，没有被定义
```

正确的全局变量定义方法：

在函数调用之前就把全局变量定义好

```python
g_num1 = 100
g_num2 = 200
g_num3 = 300

def print_global_num1():
    print("g_num1:{}".format(g_num1))
def print_global_num2():
    print("g_num2:{}".format(g_num2))
def print_global_num3():
    print("g_num3:{}".format(g_num3))

print_global_num1()
print_global_num2()
print_global_num3()
```

全局变量的类型为字典、列表时，在函数体内修改你值时，可不使用global关键字。

```python
g_num_list = [1,2,3]
g_info_dict = {"name":"zhangsan", "age":20}
def update_info():
    g_num_list.append(4)# 并没有使用global关键字
    g_info_dict["gender"] = "male"
def get_info():
    for num in g_num_list:
        print(num,end= " ")
    for key,value in g_info_dict.items():
        print("{}:{}".format(key, value))

update_info()
get_info()
# 1 2 3 4
# name:zhangsan
# age:20
# gender:male
```

## 函数缺省参数、不定长参数、命名参数

* 缺省(默认)参数
  * 函数定义带有初始值的形参
  * 函数调用时，缺省参数可传，也可不传
  * 缺省参数一定要位于参数列表的最后
  * 缺省参数数量没有限制
* 命名参数
  * 调用带有参数的函数时，通过指定参数名称传入参数的值
  * 可以不按函数定义的参数顺序传入
* 不定长参数
  * 函数可以接受不定个数的参数传入
  * def function(\[formal\_args,]\*args)函数调用时，传入的不定参数会被封装成元组
  * def function(\[formal\_args,]\*\*args)函数调用时，如果传入key=value形式的不定长参数，会被封装成字典
* 拆包
  * 对于定义了不定长参数的函数，在函数调用时需要把已定义好的元组或者列表传入到函数中，需要使用拆包方法

缺省参数

```python
def x_y_sum(x, y=20):
    rs = x + y
    print("{}+{}={}".format(x,y,rs))

x_y_sum(10, 30)# 10+30=40
x_y_sum(10)# 10+20=30
```

命名参数

```python
def x_y_sum(x=10, y=20):
    rs = x + y
    print("{}+{}={}".format(x, y, rs))

num1 = 15
num2 = 12
x_y_sum(y=num1, x=num2)
# 12+15=27
```

不定长参数

1、元组：\*args

```python
# 计算任意数字的和
def any_num_sum(x, y=10, *args):
    print("args:{}".format(args))
    rs = x + y
    if len(args) > 0:
        for arg in args:
            rs += arg
    print("计算结果：{}".format(rs))

# any_num_sum(20)
# any_num_sum(20,30)
any_num_sum(20,30,40,50)
# args:(40, 50) 元组
# 计算结果：140
```

2、字典：\*\*args

接受key:value对，然后封装到字典里

```python
# 缴五险一金
def social_comp(basic_money, **proportion):
    print("缴费基数：{}".format(basic_money))
    print("缴费比例：{}".format(proportion))

social_comp(8000, e=0.1, a=0.12)
# 缴费基数：8000
# 缴费比例：{'e': 0.1, 'a': 0.12}
```

不定长参数综合使用+拆包

```python
# 工资计算器
def salary_comp(basic_money, *other_money, **proportion):
    print("基本工资：{}".format(basic_money))
    print("其他福利：{}".format(other_money))
    print("计费比例：{}".format(proportion))
other_money = (500,200,100,1000)
proportion_dict = {"e":0.2, "m":0.1, "a":0.12}

# 注意要用*和**来拆包，不然就会把最后两个都当作元组进行封装了
salary_comp(8000, *other_money, **proportion_dict)
# 基本工资：8000
# 其他福利：(500, 200, 100, 1000)
# 计费比例：{'e': 0.2, 'm': 0.1, 'a': 0.12}
```

## 递归函数及应用

* 函数调用自身
* 注意：递归过程中要有用于结束递归的判断

递归函数

```python
# 阶乘
'''
1! = 1
1! = 2*1!
3! = 3*2!
'''
# for循环计算阶乘
def recursive_for(num):
    rs = num
    for i in range(1,num):
        rs *= i
    return rs
# 递归计算阶乘
def recursive(num):
    if num > 1:
        return num * recursive(num-1)
    else:
        return num

num = recursive_for(4)
print(num)
num = recursive(4)
print(num)
```

## 匿名函数及应用

匿名函数：定义的函数没有名称

* 用lambda关键字创建匿名函数
* 定义：lambda\[参数列表]:表达式
* 匿名函数可以作为参数被传入其他函数

匿名函数

```python
# 匿名函数
sum = lambda  x,y: x+y
print(sum(10,20))# 30
print(type(sum))# <class 'function'>
```

应用场景：

* 作为函数的参数

  ```python
  def x_y_comp(x,y,func):
      rs = func(x,y)
      print("计算结果：{}".format(rs))

  x_y_comp(3,5,lambda x,y:x+y)# 计算结果：8
  x_y_comp(3,5,lambda x,y:x*y)# 计算结果：15
  ```
* 作为内置函数的参数

  ```python
  user_info = [{"name":"zhangsan","age":20},{"name":"lisi","age":15},{"name":"wangwu","age":30},]
  print(user_info)
  # 按照年龄的降序排列，默认是升序
  user_info.sort(key=lambda info:info["age"], reverse=True)
  print(user_info)
  ```

## python内置函数

### enumerate()

enumerate() 函数用于将一个**可遍历的数据对象**(如**列表**、**元组**或**字符串**)组合为一个索引序列，同时列出数据和数据下标，一般用在 for 循环当中。

以下是 enumerate() 方法的语法:

```python
enumerate(sequence, [start=0])
```

参数：

* sequence -- 一个序列、迭代器或其他支持迭代对象。
* start -- 下标起始位置。

返回值：

返回 enumerate(枚举) 对象。

实例：

```python
seasons = ['Spring', 'Summer', 'Fall', 'Winter']
list(enumerate(seasons))
# [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
list(enumerate(seasons, start=1))       # 下标从 1 开始
# [(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
```

for循环使用 enumerate：

```python
seq = ['one', 'two', 'three']
for i, element in enumerate(seq):
    print i, element

#0 one
#1 two
#2 three
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://luweikxy.gitbook.io/machine-learning-notes/python/grammar/function.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
