# 12.函数

## 1. 函数的定义

```python
def 函数名（参数列表）:
    函数体
```

Python中的函数以 `def` 关键字定义，后接 **函数名**，**参数列表**在 `()` 中，`:` 之后接**函数体**\
​

#### Tip

**python**中的函数不显示指定返回值类型，根据 **return语句** 的返回值自动判断。 如果没有 **return** 语句，则返回 None\
​

## 2. 参数传递

python 中的一切都是对象，变量中保存的是对象的地址。

因此函数中的参数传递方式就是引用传递(指针传递)。但是需要注意的是 python 中的对象分为 **可变类型** 和 **不可变类型**。

* **不可变类型**：作为参数传递到函数中后，不能修改对象的值，只能够修改参数变量中保存的对象地址. 这样的表现则像是值传递(尽管事实上并不是)

  不可变类型有 numbers，str，tuple，

```python

def change(a):
    print(id(a))   # 指向的是同一个对象
    a=10
    print(id(a))   # 一个新对象
 
a=1
print(id(a))
change(a)

'''
4344209672
4344209672
4344209960
'''

```

* **可变类型** : 可变类型的表现就完全是正常的引用传递

## 3. 参数类型

python中的参数分为：

* 必需参数
* 关键字参数
* 默认参数
* 不定长参数

#### 必需参数

**必需参数**必须是按照声明时的顺序，数量进行传递，否则会出现语法错误

```python
def min(a,b):
    if a > b :
        return b
    else :
        return a

print(min(11)) # 报错，缺少一个参数
```

![](https://pic.existorlive.cn/202112030147517.png)

#### 关键字参数

参数在传递时以**参数名**作为**关键字**，这样参数就不是必须以声明时的顺序传递

```python
print(min(b=11,a=2))    # a,b的顺序可以颠倒
```

#### 默认参数

参数在声明时可以指定默认参数

```python
#可写函数说明
def printinfo( name, age = 35 ):
   "打印任何传入的字符串"
   print ("名字: ", name)
   print ("年龄: ", age)
   return
 
#调用printinfo函数
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )
```

注意一点，同 C++/Swift 一样，默认参数后的参数也必须是默认参数

#### 不定长参数

你可能需要一个函数能处理比当初声明时更多的参数。

```python
def functionname([formal_args,] *var_args_tuple ):
   "函数_文档字符串"
   function_suite
   return [expression]

def functionname([formal_args,] **var_args_dict ):
   "函数_文档字符串"
   function_suite
   return [expression]
```

\[ \*参数名 ], 在函数内使用时是一个元组

\[ \*\*参数名 ] 在函数内使用时是一个字典

```python
# 可写函数说明
def printinfo( arg1, *vartuple ):
   "打印任何传入的参数"
   print ("输出: ")
   print (arg1)
   for var in vartuple:
      print (var)
   return
 
# 调用printinfo 函数
printinfo( 10 )
printinfo( 70, 60, 50 )

# 可写函数说明
def printinfo( arg1, **vardict ):
   "打印任何传入的参数"
   print ("输出: ")
   print (arg1)
   print (vardict)
 
# 调用printinfo 函数
printinfo(1, a=2,b=3)
```

## 4. 匿名函数/lambda表达式

python中使用 **lambda** 关键字创建匿名函数

```python
lambda [arg1 [,arg2,.....argn]]:expression
```

**lambda** 关键字后直接跟 **参数列表** 和 **函数体**，不需要函数名

```python
# 可写函数说明
sum = lambda arg1, arg2: arg1 + arg2
 
# 调用sum函数
print ("相加后的值为 : ", sum( 10, 20 ))
print ("相加后的值为 : ", sum( 20, 20 ))
```

* lambda 只是一个表达式，函数体比 def 简单很多。
* lambda的主体是一个表达式，而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
* **lambda 函数拥有自己的命名空间，且不能访问自己参数列表之外或全局命名空间里的参数**。
* 虽然lambda函数看起来只能写一行，却不等同于C或C++的内联函数，后者的目的是调用小函数时不占用栈内存从而增加运行效率。
