1. Python函数基础:从零开始的编程思维构建
第一次接触Python函数时,我完全不明白为什么要把代码包装成这种形式。直到有次需要重复计算三个不同半径的圆面积,才真正理解函数的价值——把3.14*r*r这段代码重复写三遍不仅容易出错,修改公式时更要同时改三个地方。这就是函数最朴素的实用价值:封装重复逻辑,实现一次定义多次调用。
1.1 函数定义的核心语法
Python使用def关键字定义函数,基本结构如下:
python复制def 函数名(参数1, 参数2=默认值):
"""文档字符串(可选)"""
函数体
return 返回值 # 可选
新手常犯的错误是忽略冒号和缩进。有次我调试半小时才发现是因为函数体没有缩进四个空格,导致Python解释器认为这些代码不属于函数定义。记住:在Python中,缩进不是风格问题,而是语法要求。
1.2 参数传递的三种基本方式
- 位置参数:最常见的传参方式,按定义顺序传递
python复制def greet(name, message):
print(f"{name}, {message}")
greet("Alice", "Good morning") # 正确
greet("Good morning", "Alice") # 顺序错误!
- 关键字参数:通过参数名指定,顺序不重要
python复制greet(message="Good morning", name="Alice") # 明确指定参数名
- 默认参数:定义时指定默认值,调用时可省略
python复制def greet(name, message="Hello"):
print(f"{name}, {message}")
greet("Bob") # 输出:Bob, Hello
重要提示:默认参数必须放在参数列表最后,且默认值应该使用不可变对象(如数字、字符串)。使用可变对象(如列表、字典)作为默认值会导致意外行为,这是Python新手常踩的坑。
1.3 返回值机制详解
Python函数通过return语句返回值,没有return或return后面不跟值时返回None。一个函数可以返回多个值(实际上是返回元组):
python复制def circle_calc(r):
area = 3.14 * r ** 2
circumference = 2 * 3.14 * r
return area, circumference # 实际上是返回(area, circumference)元组
a, c = circle_calc(5) # 元组解包
我曾见过新手这样使用返回值:
python复制result = circle_calc(5)
print("面积是:" + result[0]) # 错误!直接拼接数字和字符串
正确做法应该是:
python复制print(f"面积是:{result[0]}") # 使用f-string格式化
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 函数进阶:提升代码质量的五大技巧
2.1 类型注解与文档字符串
Python 3.5+支持类型注解(Type Hints),虽然不是强制性的,但能显著提升代码可读性和IDE的智能提示能力:
python复制from typing import List, Tuple
def process_items(items: List[str], count: int) -> Tuple[bool, int]:
"""
处理字符串列表并返回状态和数量
Args:
items: 待处理的字符串列表
count: 需要处理的数量
Returns:
包含处理状态和实际处理数量的元组
"""
success = len(items) >= count
return success, min(len(items), count)
文档字符串(Docstring)的规范写法:
- 第一行简要描述函数功能
- 空一行后详细说明
- Args部分列出所有参数及其含义
- Returns部分说明返回值
2.2 Lambda表达式的正确使用场景
Lambda是创建匿名函数的快捷方式,适用于简单操作:
python复制# 传统函数定义
def square(x):
return x ** 2
# Lambda等价形式
square = lambda x: x ** 2
最适合使用Lambda的场景:
- 作为高阶函数的参数(如map、filter、sorted)
- 需要简单回调函数时
- 临时性的简单计算
不适合使用Lambda的场景:
- 函数逻辑超过一行表达式
- 需要文档说明的复杂功能
- 会被多处复用的逻辑
2.3 闭包与装饰器实战
闭包(Closure)是指函数记住了定义时的环境变量:
python复制def make_multiplier(factor):
def multiplier(x):
return x * factor
return multiplier
double = make_multiplier(2)
print(double(5)) # 输出10
装饰器(Decorator)是闭包的典型应用,用于修改或增强函数行为:
python复制def log_time(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__}执行耗时:{time.time()-start:.4f}秒")
return result
return wrapper
@log_time
def heavy_calculation(n):
return sum(i*i for i in range(n))
heavy_calculation(1000000)
2.4 生成器函数与yield关键字
生成器函数通过yield逐步产生值,而不是一次性返回所有结果,特别适合处理大数据集:
python复制def fibonacci(limit):
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b
for num in fibonacci(1000):
print(num) # 逐个输出斐波那契数,不会一次性占用内存
2.5 错误处理与异常捕获
健壮的函数应该妥善处理可能出现的异常:
python复制def safe_divide(x, y):
try:
result = x / y
except ZeroDivisionError:
print("错误:除数不能为零")
return None
except TypeError:
print("错误:只支持数字类型")
return None
else:
print(f"{x}除以{y}等于{result}")
return result
finally:
print("除法运算完成") # 无论是否出错都会执行
3. Python函数高级特性深度解析
3.1 可变参数:*args与**kwargs
*args接收任意数量的位置参数,**kwargs接收任意数量的关键字参数:
python复制def flexible_func(a, b=2, *args, **kwargs):
print(f"固定参数:a={a}, b={b}")
print(f"额外位置参数:{args}")
print(f"额外关键字参数:{kwargs}")
flexible_func(1, 3, 4, 5, name="Alice", age=25)
实际应用场景:
- 编写需要高度灵活参数的函数
- 实现装饰器时转发任意参数
- 包装其他函数时保持参数兼容性
3.2 函数注解(Function Annotations)
Python 3.0+支持为参数和返回值添加注解(不会影响运行,仅供文档和工具使用):
python复制def repeat(text: str, count: int = 1) -> str:
"""重复文本指定次数
Args:
text: 要重复的文本
count: 重复次数,默认为1
Returns:
重复后的结果字符串
"""
return text * count
3.3 函数式编程工具
Python虽然不是纯函数式语言,但提供了一些函数式编程工具:
python复制from functools import reduce
numbers = [1, 2, 3, 4, 5]
# map应用函数到每个元素
squares = list(map(lambda x: x**2, numbers))
# filter筛选满足条件的元素
evens = list(filter(lambda x: x%2 == 0, numbers))
# reduce累积计算
product = reduce(lambda x, y: x*y, numbers)
3.4 上下文管理器与with语句
通过定义__enter__和__exit__方法可以让函数支持with语句:
python复制from contextlib import contextmanager
@contextmanager
def timer(name):
import time
start = time.time()
try:
yield
finally:
print(f"{name}耗时:{time.time()-start:.2f}秒")
with timer("计算过程"):
sum(i for i in range(1000000))
4. 常见问题与性能优化
4.1 函数执行速度优化技巧
- 局部变量访问更快:函数内部频繁使用的全局变量可以先赋值给局部变量
- 避免不必要的属性查找:将类方法赋值给局部变量再循环调用
- 使用内置函数:如map、filter通常比手动循环快
- 考虑使用functools.lru_cache:缓存重复计算结果
python复制from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
4.2 调试函数的高级技巧
- 使用
print或logging输出关键变量 - 在函数开始处添加
import pdb; pdb.set_trace()进入调试器 - 使用
inspect模块检查函数信息:
python复制import inspect
print(inspect.getsource(fibonacci)) # 查看函数源代码
print(inspect.signature(fibonacci)) # 查看函数签名
4.3 Python函数与方法的区别
| 特性 | 函数(Function) | 方法(Method) |
|---|---|---|
| 定义位置 | 模块级别 | 类内部 |
| 调用方式 | func(args) | instance.method(args) |
| 第一个参数 | 无特殊要求 | self(实例方法)或cls(类方法) |
| 存储位置 | 模块全局命名空间 | 类的__dict__中 |
4.4 函数设计的最佳实践
- 单一职责原则:一个函数只做一件事
- 合理控制函数长度:一般不超过50行
- 避免副作用:函数应该只通过返回值输出结果
- 使用描述性名称:函数名应该清晰表达其功能
- 参数数量控制:一般不超过5个,过多考虑使用对象封装
5. 实战项目:构建一个数据处理管道
让我们综合运用所学知识,构建一个完整的数据处理管道:
python复制from typing import List, Dict, Optional
from functools import partial
import csv
from datetime import datetime
def read_csv(filename: str) -> List[Dict]:
"""读取CSV文件并返回字典列表"""
with open(filename, mode='r', encoding='utf-8') as f:
return list(csv.DictReader(f))
def filter_data(data: List[Dict],
condition: callable) -> List[Dict]:
"""根据条件过滤数据"""
return [item for item in data if condition(item)]
def transform_data(data: List[Dict],
transformations: Dict[str, callable]) -> List[Dict]:
"""应用指定的转换函数到数据字段"""
result = []
for item in data:
new_item = {}
for key, value in item.items():
if key in transformations:
new_item[key] = transformations[key](value)
else:
new_item[key] = value
result.append(new_item)
return result
def save_to_csv(data: List[Dict], filename: str) -> None:
"""将数据保存到CSV文件"""
if not data:
return
with open(filename, mode='w', encoding='utf-8', newline='') as f:
writer = csv.DictWriter(f, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
# 定义转换函数
def parse_date(date_str: str, fmt: str = "%Y-%m-%d") -> Optional[datetime]:
"""尝试解析日期字符串"""
try:
return datetime.strptime(date_str, fmt)
except ValueError:
return None
def to_float(value: str) -> Optional[float]:
"""转换为浮点数"""
try:
return float(value)
except ValueError:
return None
# 使用partial预设参数
parse_standard_date = partial(parse_date, fmt="%Y/%m/%d")
# 主处理流程
def process_pipeline(input_file: str, output_file: str):
"""完整的数据处理管道"""
# 1. 读取数据
raw_data = read_csv(input_file)
# 2. 过滤无效记录
clean_data = filter_data(raw_data,
lambda x: x['price'] and x['date'])
# 3. 应用转换
transformed = transform_data(clean_data, {
'date': parse_standard_date,
'price': to_float,
'quantity': lambda x: int(x) if x.isdigit() else None
})
# 4. 最终过滤
final_data = filter_data(transformed,
lambda x: x['date'] and x['price'] is not None)
# 5. 保存结果
save_to_csv(final_data, output_file)
print(f"处理完成,原始记录{len(raw_data)}条,有效记录{len(final_data)}条")
# 使用示例
process_pipeline('sales_raw.csv', 'sales_processed.csv')
这个实战项目展示了如何:
- 将复杂任务分解为多个单一职责的函数
- 使用类型注解提高代码可读性
- 通过高阶函数实现灵活的数据处理
- 使用partial预设函数参数
- 构建可维护的数据处理管道
