# 知识库

# 2.3.2 函数调用

函数调用通过函数名和传递的参数进行，形式为 `函数名([实际参数列表])`。调用时程序跳转到函数定义处执行函数体，完成后将结果返回到调用位置。例如定义 `add(a, b)` 后执行 `x = add(5, 4)`，实参 5、4 分别传给形参 a、b。有参函数需要给形参传值，这些值称为实际参数，简称实参。

```python
def add(a, b):
    s = a + b
    return s

x = add(5, 4)   # 位置参数：5 传给 a，4 传给 b
```

实参向形参传递有三种方式。位置参数按位置一一对应。默认值参数在定义时写成 `形参名=默认值`，调用未提供则用默认值；有默认值的参数必须放在非默认值参数后面，并建议只用不可变对象作默认值。如 `def default(x, y=3)` 后，`default(2)` 中 y 取 3，`default(2, 4)` 中 y 为 4。关键字参数在调用时指定参数名和值，不必遵循定义顺序，还可跳过某些默认值参数。如 `keyParameter(z=3, y=2, x=1)` 与 `keyParameter(x=1, z=2)` 两次求和均为 6；关键字参数后面不能再有位置参数，`keyParameter(1, y=2, 3)` 是错误格式。

整型、浮点型、字符串和元组是不可变类型，改值时内存地址也变；作实参时函数内改形参不会改实参，如 `modify(y)` 后 y 仍为 5。列表、字典和集合是可变类型，就地修改时地址不变；作实参时传递内存地址，形参与实参共用存储，改形参会导致实参也变，如 `modifyList` 后原列表 a 变为 `[16, 25, 36]`。

局部变量在函数或代码块内定义，函数外无法访问。全局变量在函数外定义，作用域持续到程序结束。形参与实参可同名，其实是两个变量。lambda 表达式按 `lambda 形参列表：表达式` 创建匿名函数，表达式的值即返回值，常作函数参数，如 `t.sort(key=lambda y: y * y)` 按平方从小到大排序。常见坑：默认值参数未放后面；关键字参数后再写位置参数；误以为改不可变形参会改实参；在函数外访问局部变量。

## 关键要点
- 调用形式：`函数名([实际参数列表])`；调用时跳转到定义处执行，再返回调用位置。
- 实参按位置参数、默认值参数、关键字参数三种方式传给形参。
- 位置参数按位置一一对应；默认值参数必须放在非默认值参数后面。
- 关键字参数可不按定义顺序，也可跳过默认值参数；其后不能再有位置参数。
- 不可变类型：整型、浮点型、字符串、元组；作实参时改形参不改实参。
- 可变类型：列表、字典、集合；作实参时传地址，改形参会改实参。
- 局部变量函数外不可访问；全局变量作用域持续到程序结束；形参与实参可同名但是两个变量。
- lambda 格式：`lambda 形参列表：表达式`，常作函数参数。
- 常见坑：默认值参数位置写反、关键字参数后再写位置参数、混淆可变/不可变实参、在函数外访问局部变量。
