# Python 函数进阶

## 学习目标
- 理解变量的作用域与 LEGB 规则
- 掌握 `global` 和 `nonlocal` 关键字
- 学会使用 lambda 表达式
- 理解高阶函数与函数作为参数

---

## 一、变量作用域

### 1.1 局部变量与全局变量

```python
# 全局变量
count = 0

def increment():
    local_count = 1   # 局部变量，只在函数内有效
    print(f"局部: {local_count}")
    print(f"全局: {count}")   # 可以读取全局变量

increment()
# 局部: 1
# 全局: 0

# print(local_count)   # NameError: 局部变量在函数外不可访问
```

### 1.2 修改全局变量

```python
counter = 0

def increment_wrong():
    # counter += 1     # UnboundLocalError! 不能这样修改全局变量
    pass

def increment_correct():
    global counter      # 声明使用全局变量
    counter += 1
    print(f"counter = {counter}")

increment_correct()   # counter = 1
increment_correct()   # counter = 2
print(counter)        # 2
```

---

## 二、LEGB 规则

Python 查找变量时遵循 **LEGB** 顺序：

| 层级 | 英文 | 说明 |
|------|------|------|
| L | Local | 局部作用域（函数内部） |
| E | Enclosing | 嵌套函数的父函数作用域 |
| G | Global | 全局作用域（模块级别） |
| B | Built-in | 内置作用域（Python 内置函数和变量） |

```python
x = "global"          # G: 全局

def outer():
    x = "enclosing"   # E: 嵌套

    def inner():
        x = "local"   # L: 局部
        print(x)      # 查找顺序: L → E → G → B

    inner()

outer()   # local
print(x)  # global
```

### 各层级示例

```python
# 1. Local（局部）
def func():
    local_var = "我在函数内"
    print(local_var)

func()
# print(local_var)   # NameError

# 2. Enclosing（嵌套）
def outer():
    enclosing_var = "我在外层函数"

    def inner():
        print(enclosing_var)   # 可以访问外层变量

    inner()

outer()   # 我在外层函数

# 3. Global（全局）
global_var = "我是全局变量"

def func():
    print(global_var)   # 可以读取

func()   # 我是全局变量

# 4. Built-in（内置）
print(len("hello"))     # len 是内置函数
print(max([1, 2, 3]))   # max 是内置函数
```

---

## 三、nonlocal 关键字

`nonlocal` 用于在嵌套函数中修改外层（非全局）变量。

```python
def counter():
    count = 0           # 外层函数的局部变量

    def increment():
        # count += 1    # UnboundLocalError!
        nonlocal count  # 声明使用外层变量
        count += 1
        return count

    def decrement():
        nonlocal count
        count -= 1
        return count

    return increment, decrement

inc, dec = counter()
print(inc())   # 1
print(inc())   # 2
print(dec())   # 1
print(inc())   # 2
```

### global vs nonlocal 对比

```python
x = "global"

def outer():
    x = "enclosing"

    def inner_global():
        global x
        x = "modified global"

    def inner_nonlocal():
        nonlocal x
        x = "modified enclosing"

    print(f"修改前: {x}")       # enclosing
    inner_nonlocal()
    print(f"nonlocal 后: {x}")  # modified enclosing

    inner_global()
    print(f"global 后: {x}")    # modified enclosing（局部不变）

outer()
print(f"全局: {x}")              # modified global
```

---

## 四、lambda 表达式

lambda 是创建小型匿名函数的简洁方式。

### 基本语法

```python
# 普通函数
def add(x, y):
    return x + y

# 等价的 lambda
add_lambda = lambda x, y: x + y

print(add(3, 5))          # 8
print(add_lambda(3, 5))   # 8
```

### lambda 的使用场景

```python
# 1. 作为排序的 key
students = [
    {"name": "Alice", "score": 85},
    {"name": "Bob", "score": 92},
    {"name": "Charlie", "score": 78},
]

# 按分数排序
students.sort(key=lambda s: s["score"], reverse=True)
print(students)
# [{'name': 'Bob', 'score': 92}, {'name': 'Alice', 'score': 85}, ...]

# 2. 配合 map()
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x ** 2, numbers))
print(squares)   # [1, 4, 9, 16, 25]

# 3. 配合 filter()
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)     # [2, 4]

# 4. 配合 reduce()
from functools import reduce
product = reduce(lambda x, y: x * y, numbers)
print(product)   # 120
```

### lambda 的限制

```python
# lambda 只能包含单个表达式，不能有多条语句
# 以下写法非法：
# f = lambda x: print(x); return x + 1

# 如果需要复杂逻辑，应该使用普通函数
def complex_func(x):
    if x > 0:
        return x * 2
    else:
        return x * 3
```

---

## 五、高阶函数

高阶函数是指接收函数作为参数，或返回函数的函数。

### 5.1 函数作为参数

```python
def apply_operation(numbers, operation):
    """接收一个函数作为参数"""
    return [operation(n) for n in numbers]

nums = [1, 2, 3, 4, 5]

# 传递不同的函数
print(apply_operation(nums, lambda x: x ** 2))   # [1, 4, 9, 16, 25]
print(apply_operation(nums, lambda x: x * 2))    # [2, 4, 6, 8, 10]
print(apply_operation(nums, abs))                # [1, 2, 3, 4, 5]
```

### 5.2 函数作为返回值

```python
def make_multiplier(n):
    """返回一个函数"""
    def multiplier(x):
        return x * n
    return multiplier

times3 = make_multiplier(3)
times5 = make_multiplier(5)

print(times3(10))   # 30
print(times5(10))   # 50
print(times3(times5(2)))   # 30
```

### 5.3 内置高阶函数

```python
numbers = [-3, -2, -1, 0, 1, 2, 3]

# map(): 对每个元素应用函数
absolute = list(map(abs, numbers))
print(absolute)   # [3, 2, 1, 0, 1, 2, 3]

# filter(): 按条件筛选
positives = list(filter(lambda x: x > 0, numbers))
print(positives)  # [1, 2, 3]

# sorted(): 排序（不修改原列表）
sorted_nums = sorted(numbers, key=lambda x: abs(x), reverse=True)
print(sorted_nums)   # [-3, 3, -2, 2, -1, 1, 0]

# zip(): 并行迭代
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
for name, age in zip(names, ages):
    print(f"{name}: {age}")

# enumerate(): 带索引迭代
for i, num in enumerate(numbers, start=1):
    print(f"{i}: {num}")
```

---

## 六、闭包（Closure）

闭包是指内部函数记住了外层函数的变量，即使外层函数已经执行完毕。

```python
def make_counter():
    count = 0

    def counter():
        nonlocal count
        count += 1
        return count

    return counter

c1 = make_counter()
c2 = make_counter()

print(c1())   # 1
print(c1())   # 2
print(c2())   # 1（独立的计数器）
print(c1())   # 3
```

闭包三要素：
1. 嵌套函数
2. 内部函数引用了外部变量
3. 外部函数返回了内部函数

---

## 七、综合示例

```python
"""
函数工厂：根据不同配置生成不同的处理函数
"""

def make_formatter(template):
    """
    创建一个格式化函数
    template: 包含 {value} 占位符的字符串
    """
    def formatter(value):
        return template.format(value=value)
    return formatter

# 创建不同的格式化器
currency = make_formatter("${value:.2f}")
percentage = make_formatter("{value:.1%}")
hex_format = make_formatter("0x{value:x}")

print(currency(123.456))       # $123.46
print(percentage(0.85))        # 85.0%
print(hex_format(255))         # 0xff

# 装饰器风格的用法
def timing_decorator(func):
    """计时装饰器"""
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - start
        print(f"{func.__name__} 耗时: {elapsed:.4f} 秒")
        return result
    return wrapper

@timing_decorator
def slow_function():
    import time
    time.sleep(0.1)
    return "done"

slow_function()
```

---

## 小结

- 变量查找遵循 **LEGB** 规则：Local → Enclosing → Global → Built-in
- `global` 修改全局变量，`nonlocal` 修改外层（非全局）变量
- `lambda` 创建匿名函数，适合简单场景
- 高阶函数接收或返回函数，`map()`、`filter()`、`sorted()` 是常用内置高阶函数
- 闭包让内部函数记住外层变量，实现数据封装

---

## 练习

1. 分析以下代码的输出，并解释 LEGB 查找过程：
   ```python
   x = 10
   def outer():
       x = 20
       def inner():
           x = 30
           print(x)
       inner()
       print(x)
   outer()
   print(x)
   ```
2. 使用 `lambda` 和 `sorted()` 将列表按字符串长度排序。
3. 编写一个函数 `make_power(n)`，返回计算 x 的 n 次方的函数。
4. 使用 `nonlocal` 实现一个计数器，支持增加、减少和重置功能。
5. 使用 `map()` 和 `filter()` 从列表中筛选出所有正数的平方。

