Appearance
Python 函数
函数是组织好的、可重复使用的代码块,用于实现单一或相关联的功能。
1. 函数的定义与调用
1.1 基本语法
python
# 使用 def 关键字定义函数
def greet(name):
"""向指定的人打招呼(这是文档字符串)"""
print(f"你好,{name}!")
# 调用函数
greet("Alice") # 你好,Alice!
greet("Bob") # 你好,Bob!
# 查看文档字符串
print(greet.__doc__) # 向指定的人打招呼(这是文档字符串)
help(greet)1.2 返回值
python
# return 返回结果,函数遇到 return 立即结束
def add(a, b):
return a + b
result = add(3, 5)
print(result) # 8
# 没有 return 或 return 后无值,返回 None
def say_hello():
print("Hello")
result = say_hello() # Hello
print(result) # None
# 返回多个值(本质是返回元组)
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([3, 1, 4, 1, 5, 9])
print(low, high) # 1 9
result = min_max([3, 1, 4, 1, 5, 9])
print(result) # (1, 9)
print(type(result)) # <class 'tuple'>1.3 空函数
python
# 用 pass 占位,后续再实现
def todo():
pass
# 或者用 ... (Ellipsis)
def not_implemented():
...2. 函数参数
2.1 位置参数
python
# 按位置一一对应传递
def power(base, exp):
return base ** exp
print(power(2, 10)) # 1024
print(power(10, 2)) # 100 (顺序不同,结果不同)2.2 默认参数
python
# 参数可以设置默认值,调用时可省略
def greet(name, greeting="你好"):
print(f"{greeting},{name}!")
greet("Alice") # 你好,Alice!
greet("Bob", "Hello") # Hello,Bob!
greet("Charlie", greeting="早上好") # 早上好,Charlie!
# ⚠️ 默认参数必须放在非默认参数后面
# def bad(a=1, b): # ❌ SyntaxError
# pass
# ⚠️ 默认参数陷阱:可变对象作为默认值
def append_to(item, lst=[]):
lst.append(item)
return lst
print(append_to(1)) # [1]
print(append_to(2)) # [1, 2] (不是 [2]!默认列表被共享了)
print(append_to(3)) # [1, 2, 3]
# ✅ 正确做法:用 None 作为默认值
def append_to_safe(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
print(append_to_safe(1)) # [1]
print(append_to_safe(2)) # [2] ✅2.3 可变参数(*args)
python
# *args 接收任意数量的位置参数,打包为元组
def total(*args):
print(type(args)) # <class 'tuple'>
return sum(args)
print(total(1, 2, 3)) # 6
print(total(1, 2, 3, 4, 5)) # 15
print(total()) # 0
# 实际应用:计算平均值
def average(*nums):
if not nums:
return 0
return sum(nums) / len(nums)
print(average(80, 90, 85)) # 85.0
# 混合使用:普通参数 + *args
def introduce(name, *hobbies):
print(f"{name} 的爱好:{', '.join(hobbies)}")
introduce("Alice", "读书", "跑步", "编程")
# Alice 的爱好:读书, 跑步, 编程2.4 关键字可变参数(**kwargs)
python
# **kwargs 接收任意数量的关键字参数,打包为字典
def print_info(**kwargs):
print(type(kwargs)) # <class 'dict'>
for key, value in kwargs.items():
print(f" {key}: {value}")
print_info(name="Alice", age=25, city="Beijing")
# name: Alice
# age: 25
# city: Beijing
# 混合使用
def create_user(name, age, **extra):
user = {"name": name, "age": age}
user.update(extra)
return user
user = create_user("Bob", 30, email="bob@test.com", phone="123")
print(user)
# {'name': 'Bob', 'age': 30, 'email': 'bob@test.com', 'phone': '123'}2.5 参数组合与顺序
python
# 参数顺序:位置参数 → 默认参数 → *args → 关键字参数 → **kwargs
def func(a, b=10, *args, key="default", **kwargs):
print(f"a={a}, b={b}")
print(f"args={args}")
print(f"key={key}")
print(f"kwargs={kwargs}")
func(1, 2, 3, 4, key="hello", x=100, y=200)
# a=1, b=2
# args=(3, 4)
# key=hello
# kwargs={'x': 100, 'y': 200}
# 万能参数签名
def universal(*args, **kwargs):
print(f"位置参数:{args}")
print(f"关键字参数:{kwargs}")
universal(1, 2, 3, name="Alice", age=25)
# 位置参数:(1, 2, 3)
# 关键字参数:{'name': 'Alice', 'age': 25}2.6 仅限关键字参数与仅限位置参数
python
# * 后面的参数必须用关键字传递(仅限关键字参数)
def connect(host, port, *, timeout=30, retry=3):
print(f"连接 {host}:{port},超时={timeout}s,重试={retry}次")
connect("localhost", 8080) # ✅
connect("localhost", 8080, timeout=10) # ✅
# connect("localhost", 8080, 10) # ❌ TypeError
# / 前面的参数必须用位置传递(仅限位置参数,Python 3.8+)
def calc(x, y, /, *, op="add"):
if op == "add":
return x + y
return x - y
print(calc(3, 5)) # 8 ✅
print(calc(3, 5, op="sub")) # -2 ✅
# print(calc(x=3, y=5)) # ❌ TypeError
# 组合使用:/ 左边仅位置,/ 和 * 之间可选,* 右边仅关键字
def example(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
example(1, 2, 3, d=4, e=5, f=6) # 1 2 3 4 5 62.7 参数解包
python
# * 解包序列为位置参数
def add(a, b, c):
return a + b + c
nums = [1, 2, 3]
print(add(*nums)) # 6 等价于 add(1, 2, 3)
t = (10, 20, 30)
print(add(*t)) # 60
# ** 解包字典为关键字参数
info = {"a": 100, "b": 200, "c": 300}
print(add(**info)) # 600 等价于 add(a=100, b=200, c=300)
# 混合解包
def greet(name, greeting, punctuation):
print(f"{greeting},{name}{punctuation}")
args = ("Alice",)
kwargs = {"greeting": "你好", "punctuation": "!"}
greet(*args, **kwargs) # 你好,Alice!3. 作用域与闭包
3.1 LEGB 规则
Python 查找变量的顺序:Local → Enclosing → Global → Built-in
python
x = "全局变量" # Global
def outer():
x = "外层函数变量" # Enclosing
def inner():
x = "内层函数变量" # Local
print(x)
inner()
print(x)
outer()
print(x)
# 内层函数变量
# 外层函数变量
# 全局变量3.2 global 和 nonlocal
python
# global —— 在函数内修改全局变量
count = 0
def increment():
global count
count += 1
increment()
increment()
print(count) # 2
# nonlocal —— 在内层函数中修改外层函数的变量
def counter():
n = 0
def increment():
nonlocal n
n += 1
return n
return increment
c = counter()
print(c()) # 1
print(c()) # 2
print(c()) # 33.3 闭包
闭包 = 内层函数 + 引用的外层变量。外层函数返回后,内层函数仍然可以访问外层的变量。
python
# 基本闭包
def make_multiplier(factor):
def multiply(x):
return x * factor # factor 被"记住"了
return multiply
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
print(double(10)) # 20
# 查看闭包引用的变量
print(double.__closure__[0].cell_contents) # 2
# 实用示例:生成问候函数
def make_greeter(greeting):
def greet(name):
return f"{greeting},{name}!"
return greet
chinese_greet = make_greeter("你好")
english_greet = make_greeter("Hello")
print(chinese_greet("Alice")) # 你好,Alice!
print(english_greet("Alice")) # Hello,Alice!
# ⚠️ 闭包常见陷阱:循环中的闭包
funcs = []
for i in range(3):
funcs.append(lambda: i) # 所有 lambda 共享同一个变量 i
print([f() for f in funcs]) # [2, 2, 2] (不是 [0, 1, 2]!)
# ✅ 解决方法:用默认参数捕获当前值
funcs = []
for i in range(3):
funcs.append(lambda x=i: x)
print([f() for f in funcs]) # [0, 1, 2] ✅4. 匿名函数 lambda
lambda 用于创建简短的、一次性的小函数。
python
# 语法:lambda 参数: 表达式
add = lambda a, b: a + b
print(add(3, 5)) # 8
# 等价于
def add(a, b):
return a + b
# lambda 只能包含单个表达式,不能有语句(if/for/while 等)
# 但可以使用条件表达式
check = lambda x: "偶数" if x % 2 == 0 else "奇数"
print(check(4)) # 偶数
print(check(7)) # 奇数
# lambda 最常见的用途:作为高阶函数的参数
# 排序:按绝对值排序
nums = [-5, 3, -2, 8, -1]
print(sorted(nums, key=lambda x: abs(x)))
# [-1, -2, 3, -5, 8]
# 排序:按字典的某个字段
students = [
{"name": "Alice", "score": 90},
{"name": "Bob", "score": 85},
{"name": "Charlie", "score": 92},
]
students.sort(key=lambda s: s["score"], reverse=True)
for s in students:
print(f"{s['name']}: {s['score']}")
# Charlie: 92
# Alice: 90
# Bob: 85
# 多条件排序
data = [("Alice", 90), ("Bob", 90), ("Charlie", 85)]
data.sort(key=lambda x: (-x[1], x[0])) # 分数降序,同分按姓名升序
print(data)
# [('Alice', 90), ('Bob', 90), ('Charlie', 85)]5. 高阶函数
高阶函数:接收函数作为参数,或者返回函数的函数。
5.1 map()
对可迭代对象的每个元素应用函数,返回迭代器。
python
# 基本用法
nums = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x ** 2, nums))
print(squares) # [1, 4, 9, 16, 25]
# 等价于列表推导式
squares = [x ** 2 for x in nums]
# 使用已有函数
words = ["hello", "world", "python"]
upper_words = list(map(str.upper, words))
print(upper_words) # ['HELLO', 'WORLD', 'PYTHON']
# 多个可迭代对象
a = [1, 2, 3]
b = [10, 20, 30]
result = list(map(lambda x, y: x + y, a, b))
print(result) # [11, 22, 33]
# 类型转换
str_nums = ["1", "2", "3", "4"]
int_nums = list(map(int, str_nums))
print(int_nums) # [1, 2, 3, 4]5.2 filter()
过滤可迭代对象,保留使函数返回 True 的元素。
python
# 过滤偶数
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens) # [2, 4, 6, 8, 10]
# 等价于列表推导式
evens = [x for x in nums if x % 2 == 0]
# 过滤空字符串
words = ["hello", "", "world", "", "python"]
non_empty = list(filter(None, words)) # None 表示过滤假值
print(non_empty) # ['hello', 'world', 'python']
# 过滤字典列表
users = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 17},
{"name": "Charlie", "age": 30},
{"name": "David", "age": 15},
]
adults = list(filter(lambda u: u["age"] >= 18, users))
print([u["name"] for u in adults]) # ['Alice', 'Charlie']5.3 reduce()
对序列元素进行累积运算,最终得到一个值。
python
from functools import reduce
# 累加
nums = [1, 2, 3, 4, 5]
total = reduce(lambda a, b: a + b, nums)
print(total) # 15 过程:((((1+2)+3)+4)+5)
# 累乘
product = reduce(lambda a, b: a * b, nums)
print(product) # 120
# 带初始值
total = reduce(lambda a, b: a + b, nums, 100)
print(total) # 115 (初始值 100 + 15)
# 找最大值
maximum = reduce(lambda a, b: a if a > b else b, nums)
print(maximum) # 5
# 实用示例:展平嵌套列表
nested = [[1, 2], [3, 4], [5, 6]]
flat = reduce(lambda a, b: a + b, nested)
print(flat) # [1, 2, 3, 4, 5, 6]5.4 sorted() 的 key 参数
python
# 按字符串长度排序
words = ["python", "is", "a", "great", "language"]
print(sorted(words, key=len))
# ['a', 'is', 'great', 'python', 'language']
# 忽略大小写排序
words = ["Banana", "apple", "Cherry"]
print(sorted(words, key=str.lower))
# ['apple', 'Banana', 'Cherry']
# 复杂排序:使用 operator 模块
from operator import itemgetter, attrgetter
students = [("Alice", 90), ("Bob", 85), ("Charlie", 92)]
print(sorted(students, key=itemgetter(1), reverse=True))
# [('Charlie', 92), ('Alice', 90), ('Bob', 85)]
# 多级排序
data = [("A", 2), ("B", 1), ("A", 1), ("B", 2)]
print(sorted(data, key=itemgetter(0, 1)))
# [('A', 1), ('A', 2), ('B', 1), ('B', 2)]5.5 函数作为参数和返回值
python
# 函数作为参数
def apply(func, value):
return func(value)
print(apply(abs, -10)) # 10
print(apply(str.upper, "hi")) # HI
print(apply(lambda x: x * 2, 5)) # 10
# 函数作为返回值
def make_power(n):
def power(x):
return x ** n
return power
square = make_power(2)
cube = make_power(3)
print(square(5)) # 25
print(cube(5)) # 1256. 递归函数
函数调用自身的编程技巧。需要有终止条件,否则会无限递归。
python
# 阶乘:n! = n × (n-1)!
def factorial(n):
if n <= 1: # 终止条件
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120 (5 × 4 × 3 × 2 × 1)
print(factorial(10)) # 3628800
# 斐波那契数列:F(n) = F(n-1) + F(n-2)
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
print([fib(i) for i in range(10)])
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# ⚠️ 上面的递归效率很低(大量重复计算)
# ✅ 使用缓存优化
from functools import lru_cache
@lru_cache(maxsize=None)
def fib_fast(n):
if n <= 1:
return n
return fib_fast(n - 1) + fib_fast(n - 2)
print(fib_fast(50)) # 12586269025 (瞬间完成)
print(fib_fast(100)) # 354224848179261915075
# Python 默认递归深度限制为 1000
import sys
print(sys.getrecursionlimit()) # 1000
# sys.setrecursionlimit(2000) # 可以修改,但不建议设太大
# 实用示例:递归遍历嵌套结构
def flatten(lst):
result = []
for item in lst:
if isinstance(item, list):
result.extend(flatten(item)) # 递归展平
else:
result.append(item)
return result
nested = [1, [2, [3, 4], 5], [6, 7]]
print(flatten(nested)) # [1, 2, 3, 4, 5, 6, 7]7. 函数注解与类型提示
类型提示不会影响运行,但能提高代码可读性,并配合工具做静态检查。
python
# 基本类型注解
def add(a: int, b: int) -> int:
return a + b
print(add(3, 5)) # 8
print(add("a", "b")) # ab (类型注解不强制,运行时不报错)
# 常见类型注解
def greet(name: str) -> str:
return f"Hello, {name}"
def is_even(n: int) -> bool:
return n % 2 == 0
def process(data: list) -> None:
print(data)
# 使用 typing 模块提供更精确的类型
from typing import Optional, Union
# Optional 表示可以是指定类型或 None
def find_user(user_id: int) -> Optional[str]:
users = {1: "Alice", 2: "Bob"}
return users.get(user_id)
print(find_user(1)) # Alice
print(find_user(99)) # None
# Union 表示可以是多种类型之一
def double(x: Union[int, str]) -> Union[int, str]:
if isinstance(x, int):
return x * 2
return x + x
print(double(5)) # 10
print(double("hi")) # hihi
# Python 3.10+ 可以用 | 替代 Union
# def double(x: int | str) -> int | str:
# 容器类型注解
from typing import List, Dict, Tuple
def average(scores: List[float]) -> float:
return sum(scores) / len(scores)
def get_info() -> Dict[str, int]:
return {"age": 25, "score": 90}
def get_point() -> Tuple[int, int]:
return (3, 4)
# Python 3.9+ 可以直接用内置类型
# def average(scores: list[float]) -> float:
# def get_info() -> dict[str, int]:
# 查看函数注解
print(add.__annotations__)
# {'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}8. functools 常用工具
8.1 partial —— 偏函数
固定函数的部分参数,生成新函数。
python
from functools import partial
# 固定 base 参数
def power(base, exp):
return base ** exp
square = partial(power, exp=2)
cube = partial(power, exp=3)
print(square(5)) # 25
print(cube(5)) # 125
# 实用示例:简化 int 的进制转换
int2 = partial(int, base=2) # 二进制转整数
int16 = partial(int, base=16) # 十六进制转整数
print(int2("1010")) # 10
print(int16("ff")) # 255
# 简化 print
debug = partial(print, "[DEBUG]")
debug("程序启动") # [DEBUG] 程序启动
debug("加载配置") # [DEBUG] 加载配置8.2 lru_cache —— 缓存装饰器
python
from functools import lru_cache
# 自动缓存函数结果,相同参数不会重复计算
@lru_cache(maxsize=128)
def expensive_calc(n):
print(f" 计算 {n}...") # 只有首次调用时打印
return n ** 2
print(expensive_calc(4)) # 计算 4... → 16
print(expensive_calc(4)) # 16 (直接返回缓存,不再打印"计算")
print(expensive_calc(5)) # 计算 5... → 25
# 查看缓存信息
print(expensive_calc.cache_info())
# CacheInfo(hits=1, misses=2, maxsize=128, currsize=2)
# 清除缓存
expensive_calc.cache_clear()
# Python 3.9+ 可以用 @cache,等价于 @lru_cache(maxsize=None)
from functools import cache
@cache
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
print(fib(100)) # 3542248481792619150758.3 wraps —— 保留函数元信息
python
from functools import wraps
# 不使用 wraps 的问题
def my_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@my_decorator
def say_hello():
"""这是 say_hello 的文档"""
print("Hello!")
print(say_hello.__name__) # wrapper (函数名丢失了!)
print(say_hello.__doc__) # None (文档也丢失了!)
# ✅ 使用 wraps 保留原函数信息
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@my_decorator
def say_hello():
"""这是 say_hello 的文档"""
print("Hello!")
print(say_hello.__name__) # say_hello ✅
print(say_hello.__doc__) # 这是 say_hello 的文档 ✅9. 内置函数补充
9.1 eval() / exec()
python
# eval() —— 执行表达式并返回结果
print(eval("3 + 5")) # 8
print(eval("'hello'.upper()")) # HELLO
x = 10
print(eval("x * 2")) # 20
# exec() —— 执行语句(无返回值)
exec("y = 100")
print(y) # 100
exec("""
def dynamic_func(n):
return n * 2
""")
print(dynamic_func(5)) # 10
# ⚠️ 安全警告:永远不要对用户输入使用 eval/exec
# eval(input("输入表达式:")) # 极其危险!9.2 zip() 进阶用法
python
# 基本用法
names = ["Alice", "Bob", "Charlie"]
scores = [90, 85, 92]
print(list(zip(names, scores)))
# [('Alice', 90), ('Bob', 85), ('Charlie', 92)]
# 构建字典
name_score = dict(zip(names, scores))
print(name_score) # {'Alice': 90, 'Bob': 85, 'Charlie': 92}
# 解压(zip 的逆操作)
pairs = [("Alice", 90), ("Bob", 85), ("Charlie", 92)]
names, scores = zip(*pairs)
print(names) # ('Alice', 'Bob', 'Charlie')
print(scores) # (90, 85, 92)
# 矩阵转置
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transposed = [list(row) for row in zip(*matrix)]
print(transposed) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
# strict 模式(Python 3.10+),长度不等时报错
# list(zip([1, 2], [3, 4, 5], strict=True)) # ValueError9.3 enumerate() 进阶
python
# 指定起始索引
fruits = ["apple", "banana", "cherry"]
for i, fruit in enumerate(fruits, start=1):
print(f"{i}. {fruit}")
# 1. apple
# 2. banana
# 3. cherry
# 实用:查找元素的所有索引
nums = [1, 3, 5, 3, 7, 3, 9]
indices = [i for i, x in enumerate(nums) if x == 3]
print(indices) # [1, 3, 5]10. 综合示例
示例 1:简易计算器
python
def calculator(a, b, op="+"):
ops = {
"+": lambda x, y: x + y,
"-": lambda x, y: x - y,
"*": lambda x, y: x * y,
"/": lambda x, y: x / y if y != 0 else "除数不能为零",
}
func = ops.get(op)
if func is None:
return f"不支持的运算符:{op}"
return func(a, b)
print(calculator(10, 3, "+")) # 13
print(calculator(10, 3, "-")) # 7
print(calculator(10, 3, "*")) # 30
print(calculator(10, 3, "/")) # 3.3333333333333335
print(calculator(10, 0, "/")) # 除数不能为零
print(calculator(10, 3, "%")) # 不支持的运算符:%示例 2:通用重试函数
python
import random
from functools import wraps
def retry(max_attempts=3):
"""重试装饰器"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(1, max_attempts + 1):
try:
return func(*args, **kwargs)
except Exception as e:
print(f" 第 {attempt} 次尝试失败:{e}")
if attempt == max_attempts:
raise
return wrapper
return decorator
@retry(max_attempts=5)
def unstable_task():
"""模拟不稳定的操作"""
if random.random() < 0.7:
raise ConnectionError("连接失败")
return "成功!"
try:
result = unstable_task()
print(result)
except ConnectionError:
print("多次重试后仍然失败")示例 3:管道式数据处理
python
def pipeline(data, *functions):
"""将数据依次通过多个函数处理"""
result = data
for func in functions:
result = func(result)
return result
# 定义处理步骤
remove_spaces = lambda s: s.strip()
to_lower = lambda s: s.lower()
replace_spaces = lambda s: s.replace(" ", "_")
add_prefix = lambda s: f"user_{s}"
# 组合使用
username = pipeline(
" Hello World ",
remove_spaces,
to_lower,
replace_spaces,
add_prefix,
)
print(username) # user_hello_world11. 总结
| 概念 | 说明 | 示例 |
|---|---|---|
def | 定义函数 | def add(a, b): return a + b |
return | 返回值 | return x, y (返回元组) |
*args | 可变位置参数 | def f(*args) → 元组 |
**kwargs | 可变关键字参数 | def f(**kwargs) → 字典 |
lambda | 匿名函数 | lambda x: x * 2 |
global | 声明全局变量 | global count |
nonlocal | 声明外层变量 | nonlocal n |
| 闭包 | 内层函数 + 外层变量 | 函数工厂模式 |
| 类型提示 | 提高可读性 | def add(a: int) -> int |
lru_cache | 缓存函数结果 | @lru_cache(maxsize=128) |
partial | 固定部分参数 | partial(int, base=2) |
函数设计原则
python
# 1. 单一职责:一个函数只做一件事
# ✅ 好
def calculate_total(prices):
return sum(prices)
def format_price(amount):
return f"¥{amount:.2f}"
# ❌ 不好:既计算又格式化
def calculate_and_format(prices):
total = sum(prices)
return f"¥{total:.2f}"
# 2. 合理使用默认参数,避免可变默认值
# 3. 函数名用小写加下划线(snake_case)
# 4. 优先使用返回值而非修改全局变量
# 5. 文档字符串说明参数和返回值的含义