python:第三章函数
目录
第三章 函数
本章概要
函数是组织好的、可重复使用的代码块,用于实现单一或相关联的功能。本章将深入学习Python函数的定义、参数传递、返回值、lambda表达式和装饰器等高级特性。
3.1 函数基础
3.1.1 定义函数
使用 ``def`` 关键字定义函数。
# 基本函数定义 def greet(): """这是一个问候函数""" print("Hello, World!") # 调用函数 greet() # Hello, World!
3.1.2 函数参数
# 带参数的函数 def greet_person(name): """向指定的人问候""" print(f"Hello, {name}!") greet_person("Alice") # Hello, Alice! greet_person("Bob") # Hello, Bob! # 多个参数 def add(a, b): """返回两个数的和""" return a + b result = add(3, 5) print(result) # 8
3.1.3 返回值
# 返回单个值 def square(x): return x ** 2 # 返回多个值(实际是返回元组) def get_min_max(numbers): return min(numbers), max(numbers) minimum, maximum = get_min_max([3, 1, 4, 1, 5, 9]) print(f"最小值: {minimum}, 最大值: {maximum}") # 没有return语句,默认返回None def print_message(msg): print(msg) result = print_message("Hello") print(result) # None
3.1.4 文档字符串
def calculate_area(length, width): """ 计算矩形的面积。 参数: length (float): 矩形的长度 width (float): 矩形的宽度 返回: float: 矩形的面积 示例: >>> calculate_area(5, 3) 15 """ return length * width # 查看文档字符串 print(calculate_area.__doc__) help(calculate_area)
3.2 参数类型
3.2.1 位置参数
按照位置顺序传递参数。
def power(base, exponent): return base ** exponent print(power(2, 3)) # 8 (2的3次方) print(power(3, 2)) # 9 (3的2次方)
3.2.2 关键字参数
通过参数名传递,可以任意顺序。
def introduce(name, age, city): print(f"我叫{name},今年{age}岁,来自{city}") # 关键字参数 introduce(age=25, city="北京", name="张三") # 混合使用(位置参数必须在关键字参数之前) introduce("李四", city="上海", age=30)
3.2.3 默认参数值
def greet(name, greeting="Hello"): print(f"{greeting}, {name}!") greet("Alice") # Hello, Alice! greet("Bob", "Hi") # Hi, Bob! greet("Charlie", greeting="Hey") # Hey, Charlie!
⚠️ 警告:默认参数的陷阱
# 错误示例 def append_item(item, item_list=[]): item_list.append(item) return item_list print(append_item(1)) # [1] print(append_item(2)) # [1, 2] - 意外!列表被保留了 # 正确做法 def append_item(item, item_list=None): if item_list is None: item_list = [] item_list.append(item) return item_list print(append_item(1)) # [1] print(append_item(2)) # [2] - 正确
3.2.4 可变参数 *args
接收任意数量的位置参数。
def sum_all(*args): """计算所有参数的和""" total = 0 for num in args: total += num return total # 调用方式 print(sum_all(1, 2, 3)) # 6 print(sum_all(1, 2, 3, 4, 5)) # 15 print(sum_all()) # 0 # args是一个元组 print(type(args)) # <class 'tuple'>
3.2.5 关键字可变参数 **kwargs
接收任意数量的关键字参数。
def print_info(**kwargs): """打印所有关键字参数""" for key, value in kwargs.items(): print(f"{key}: {value}") print_info(name="Alice", age=25, city="北京") # 输出: # name: Alice # age: 25 # city: 北京 # kwargs是一个字典 print(type(kwargs)) # <class 'dict'>
3.2.6 参数顺序规则
正确的参数顺序:
def func(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2, **kwargs): """ 参数顺序: 1. 仅限位置参数 (/ 之前) 2. 位置或关键字参数 (/ 和 * 之间) 3. 仅限关键字参数 (* 之后) 4. **kwargs """ pass # 示例 def combined(a, b, /, c, d, *args, e, f, **kwargs): print(f"a={a}, b={b}, c={c}, d={d}") print(f"args={args}") print(f"e={e}, f={f}") print(f"kwargs={kwargs}") combined(1, 2, 3, 4, 5, 6, e=7, f=8, g=9, h=10)
3.2.7 解包参数
# 使用*解包列表/元组 def add(a, b, c): return a + b + c numbers = [1, 2, 3] print(add(*numbers)) # 6 # 使用**解包字典 def create_user(name, age, email): return {"name": name, "age": age, "email": email} user_data = {"name": "Alice", "age": 25, "email": "alice@example.com"} user = create_user(**user_data) print(user)
3.3 变量作用域
3.3.1 局部变量和全局变量
# 全局变量 global_var = "我在函数外" def demo(): # 局部变量 local_var = "我在函数内" print(local_var) # 可以访问局部变量 print(global_var) # 可以访问全局变量 demo() print(global_var) # 可以访问全局变量 # print(local_var) # 错误!不能访问局部变量
3.3.2 global 关键字
在函数内修改全局变量。
counter = 0 def increment(): global counter counter += 1 print(f"计数器: {counter}") increment() # 计数器: 1 increment() # 计数器: 2 print(counter) # 2
3.3.3 nonlocal 关键字
在嵌套函数中修改外层(非全局)变量。
def outer(): x = "外部" def inner(): nonlocal x x = "内部修改" print(f"inner: {x}") inner() print(f"outer: {x}") outer() # 输出: # inner: 内部修改 # outer: 内部修改
3.3.4 作用域规则(LEGB)
Python查找变量的顺序:
1. **L**ocal - 局部作用域 2. **E**nclosing - 嵌套函数的外层作用域 3. **G**lobal - 全局作用域 4. **B**uilt-in - 内置作用域
x = "global" # Global def outer(): x = "enclosing" # Enclosing def inner(): x = "local" # Local print(x) # 输出: local inner() print(x) # 输出: enclosing outer() print(x) # 输出: global
3.4 高级函数特性
3.4.1 函数作为对象
在Python中,函数是一等对象,可以像其他对象一样传递。
def greet(name): return f"Hello, {name}!" # 将函数赋值给变量 say_hello = greet print(say_hello("Alice")) # Hello, Alice! # 函数作为参数 def execute_function(func, arg): return func(arg) result = execute_function(greet, "Bob") print(result) # Hello, Bob! # 函数作为返回值 def create_multiplier(n): def multiplier(x): return x * n return multiplier double = create_multiplier(2) triple = create_multiplier(3) print(double(5)) # 10 print(triple(5)) # 15
3.4.2 闭包
闭包是引用了外部变量但在外部作用域执行的函数。
def make_power(exponent): """创建幂函数""" def power(base): return base ** exponent return power square = make_power(2) cube = make_power(3) print(square(4)) # 16 print(cube(2)) # 8 # 查看闭包信息 print(square.__closure__) # 查看闭包单元 print(square.__closure__[0].cell_contents) # 2 (exponent的值)
3.4.3 匿名函数(lambda)
lambda用于创建小型匿名函数。
# 基本语法 square = lambda x: x ** 2 print(square(5)) # 25 # 多个参数 add = lambda x, y: x + y print(add(3, 4)) # 7 # 默认参数 greet = lambda name, greeting="Hello": f"{greeting}, {name}!" print(greet("Alice")) # Hello, Alice! print(greet("Bob", "Hi")) # Hi, Bob!
常用场景
# 作为高阶函数的参数 numbers = [1, 2, 3, 4, 5] # map() squares = list(map(lambda x: x ** 2, numbers)) print(squares) # [1, 4, 9, 16, 25] # filter() evens = list(filter(lambda x: x % 2 == 0, numbers)) print(evens) # [2, 4] # sorted()的key参数 students = [("Alice", 85), ("Bob", 92), ("Charlie", 78)] sorted_by_score = sorted(students, key=lambda x: x[1], reverse=True) print(sorted_by_score) # [('Bob', 92), ('Alice', 85), ('Charlie', 78)] # reduce() from functools import reduce product = reduce(lambda x, y: x * y, numbers) print(product) # 120
3.4.4 递归函数
函数调用自身。
# 阶乘 def factorial(n): if n <= 1: return 1 return n * factorial(n - 1) print(factorial(5)) # 120 # 斐波那契数列 def fibonacci(n): if n <= 1: return n return fibonacci(n - 1) + fibonacci(n - 2) print([fibonacci(i) for i in range(10)]) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] # 尾递归优化(Python不支持尾递归优化) def factorial_tail(n, acc=1): if n <= 1: return acc return factorial_tail(n - 1, n * acc) print(factorial_tail(5)) # 120
3.4.5 装饰器
装饰器是修改函数行为的强大工具。
基本装饰器
def my_decorator(func): def wrapper(*args, **kwargs): print("函数执行前") result = func(*args, **kwargs) print("函数执行后") return result return wrapper @my_decorator def say_hello(): print("Hello!") say_hello() # 输出: # 函数执行前 # Hello! # 函数执行后
带参数的装饰器
def repeat(times): """重复执行函数的装饰器""" def decorator(func): def wrapper(*args, **kwargs): for _ in range(times): result = func(*args, **kwargs) return result return wrapper return decorator @repeat(times=3) def greet(name): print(f"Hello, {name}!") greet("Alice") # 输出三次: Hello, Alice!
使用functools.wraps
from functools import wraps def my_decorator(func): @wraps(func) # 保留原函数的元数据 def wrapper(*args, **kwargs): """包装函数""" print("执行函数...") return func(*args, **kwargs) return wrapper @my_decorator def example(): """示例函数""" print("Hello") print(example.__name__) # example (不使用wraps会显示wrapper) print(example.__doc__) # 示例函数
常用装饰器示例
import time from functools import wraps # 计时装饰器 def timer(func): @wraps(func) 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 # 缓存装饰器(简单的memoization) def memoize(func): cache = {} @wraps(func) def wrapper(*args): if args not in cache: cache[args] = func(*args) return cache[args] return wrapper @timer @memoize def fib(n): if n < 2: return n return fib(n - 1) + fib(n - 2) print(fib(30))
3.5 函数式编程工具
3.5.1 map()
将函数应用于可迭代对象的每个元素。
numbers = [1, 2, 3, 4, 5] # 使用lambda squares = list(map(lambda x: x ** 2, numbers)) # 使用内置函数 lengths = list(map(len, ["apple", "banana", "cherry"])) # 多个可迭代对象 sums = list(map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6])) print(sums) # [5, 7, 9]
3.5.2 filter()
根据条件筛选元素。
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 筛选偶数 evens = list(filter(lambda x: x % 2 == 0, numbers)) # 筛选非空字符串 strings = ["hello", "", "world", "", "python"] non_empty = list(filter(None, strings)) print(non_empty) # ['hello', 'world', 'python']
3.5.3 reduce()
累积计算。
from functools import reduce numbers = [1, 2, 3, 4, 5] # 求和 sum_result = reduce(lambda x, y: x + y, numbers) print(sum_result) # 15 # 求积 product = reduce(lambda x, y: x * y, numbers) print(product) # 120 # 找最大值 maximum = reduce(lambda x, y: x if x > y else y, numbers) print(maximum) # 5 # 带初始值 sum_with_initial = reduce(lambda x, y: x + y, numbers, 100) print(sum_with_initial) # 115
3.5.4 zip()
# 并行迭代 names = ["Alice", "Bob", "Charlie"] ages = [25, 30, 35] for name, age in zip(names, ages): print(f"{name}: {age}") # 创建字典 keys = ["a", "b", "c"] values = [1, 2, 3] d = dict(zip(keys, values)) print(d) # {'a': 1, 'b': 2, 'c': 3} # 处理不等长序列 from itertools import zip_longest list1 = [1, 2, 3] list2 = ["a", "b"] for x, y in zip_longest(list1, list2, fillvalue="-"): print(x, y)
3.5.5 其他工具函数
# enumerate() for i, char in enumerate("Python", start=1): print(f"{i}: {char}") # sorted() numbers = [3, 1, 4, 1, 5, 9] sorted_numbers = sorted(numbers) reversed_numbers = sorted(numbers, reverse=True) # all() / any() print(all([True, True, False])) # False print(any([False, True, False])) # True print(all(x > 0 for x in [1, 2, 3])) # True # reversed() for char in reversed("Python"): print(char, end="") # nohtyP
3.6 代码示例
示例1:缓存装饰器
from functools import wraps def lru_cache(maxsize=128): """简单的LRU缓存装饰器""" def decorator(func): cache = {} order = [] @wraps(func) def wrapper(*args): if args in cache: # 移动到最近使用 order.remove(args) order.append(args) return cache[args] result = func(*args) cache[args] = result order.append(args) # 超出限制,删除最久未使用的 if len(cache) > maxsize: oldest = order.pop(0) del cache[oldest] return result return wrapper return decorator @lru_cache(maxsize=3) def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) print(fibonacci(50))
示例2:函数注册器
class FunctionRegistry: """函数注册器 - 用于注册和调用函数""" def __init__(self): self._functions = {} def register(self, name=None): """装饰器:注册函数""" def decorator(func): func_name = name or func.__name__ self._functions[func_name] = func return func return decorator def call(self, name, *args, **kwargs): """调用已注册的函数""" if name not in self._functions: raise ValueError(f"未知函数: {name}") return self._functions[name](*args, **kwargs) def list_functions(self): """列出所有注册的函数""" return list(self._functions.keys()) # 使用示例 registry = FunctionRegistry() @registry.register() def add(a, b): return a + b @registry.register("multiply") def mul(a, b): return a * b print(registry.list_functions()) # ['add', 'multiply'] print(registry.call("add", 3, 4)) # 7 print(registry.call("multiply", 3, 4)) # 12
3.7 练习题
练习1:计算圆的相关值
编写函数,根据半径计算圆的面积和周长。
import math def circle_properties(radius): """返回圆的面积和周长""" area = math.pi * radius ** 2 circumference = 2 * math.pi * radius return area, circumference # 测试 r = 5 area, circumference = circle_properties(r) print(f"半径为{r}的圆:") print(f" 面积: {area:.2f}") print(f" 周长: {circumference:.2f}")
练习2:验证器装饰器
编写装饰器验证函数参数是否为正数。
from functools import wraps def validate_positive(func): """验证所有参数为正数""" @wraps(func) def wrapper(*args, **kwargs): for arg in args: if isinstance(arg, (int, float)) and arg <= 0: raise ValueError(f"参数必须为正数,得到: {arg}") return func(*args, **kwargs) return wrapper @validate_positive def rectangle_area(width, height): return width * height print(rectangle_area(5, 3)) # 15 # print(rectangle_area(-5, 3)) # ValueError
练习3:柯里化
实现函数柯里化(将多参数函数转为单参数函数链)。
from functools import partial def curry(func): """柯里化装饰器""" def curried(*args, **kwargs): if len(args) + len(kwargs) >= func.__code__.co_argcount: return func(*args, **kwargs) return partial(curried, *args, **kwargs) return curried @curry def add_three(a, b, c): return a + b + c # 使用 print(add_three(1)(2)(3)) # 6 print(add_three(1, 2)(3)) # 6 print(add_three(1)(2, 3)) # 6 add_five = add_three(5) print(add_five(10)(20)) # 35
练习4:函数组合
实现函数组合(compose)。
from functools import reduce def compose(*functions): """函数组合: compose(f, g, h)(x) = f(g(h(x)))""" def composed(x): return reduce(lambda v, f: f(v), reversed(functions), x) return composed # 使用 add_one = lambda x: x + 1 double = lambda x: x * 2 square = lambda x: x ** 2 transform = compose(square, double, add_one) # 等价于: square(double(add_one(x))) print(transform(3)) # (3+1)*2 squared = 64
本章小结
本章学习了Python函数的核心概念:
- 函数定义 - def、参数、返回值、文档字符串
- 参数类型 - 位置参数、关键字参数、默认参数、*args、kwargs * 作用域 - 局部变量、全局变量、global、nonlocal、LEGB规则 * 高级特性 - 函数作为对象、闭包、lambda、递归 * 装饰器 - 基本装饰器、带参数的装饰器、常用装饰器模式 * 函数式编程** - map、filter、reduce、zip等工具函数
掌握函数后,你可以编写模块化、可重用的代码了。下一章将学习Python的内置数据结构。
进一步阅读
python/第三章函数.txt · 最后更改: 由 127.0.0.1
