函数
函数是组织好的、可重复使用的代码段,用于实现单一的功能。
1. 定义与调用
使用 def 关键字定义函数。
def say_hello():
"""这是一个简单的问候函数"""
print("Hello, Python!")
# 调用函数
say_hello()
2. 参数传递
位置参数 (Positional Arguments)
按顺序传递参数。
def sub(a, b):
return a - b
print(sub(10, 3)) # 7
print(sub(3, 10)) # -7
关键字参数 (Keyword Arguments)
通过参数名指定,顺序不重要。
print(sub(b=3, a=10)) # 7
默认参数 (Default Arguments)
为参数提供默认值。注意:默认参数必须放在非默认参数之后。
def greet(name, msg="Good morning"):
print(f"{msg}, {name}")
greet("Alice") # 使用默认 msg
greet("Bob", "Good evening") # 覆盖默认 msg
可变默认参数陷阱
千万不要使用可变对象(如列表、字典)作为默认参数值!
# ❌ 错误做法
def append_to(num, target=[]):
target.append(num)
return target
print(append_to(1)) # [1]
print(append_to(2)) # [1, 2] -> 竟然记住了上次的状态!
# ✅ 正确做法
def append_to(num, target=None):
if target is None:
target = []
target.append(num)
return target
3. 返回值 (return)
- 使用
return返回结果。 - 如果没有
return,默认返回None。 - 可以返回多个值(本质是返回一个元组)。
def get_user_info():
name = "Alice"
age = 25
return name, age # 返回元组 ("Alice", 25)
n, a = get_user_info() # 解包
4. 可变长参数
用于处理不确定数量的参数。
*args: 接收任意数量的位置参数(打包成元组)。**kwargs: 接收任意数量的关键字参数(打包成字典)。
def func(required, *args, **kwargs):
print(f"Required: {required}")
print(f"Args (tuple): {args}")
print(f"Kwargs (dict): {kwargs}")
func(1, 2, 3, 4, name="Alice", val=True)
# Output:
# Required: 1
# Args (tuple): (2, 3, 4)
# Kwargs (dict): {'name': 'Alice', 'val': True}
5. 作用域 (Scope)
- Local (局部): 函数内部定义的变量。
- Global (全局): 模块级别定义的变量。
在函数内部修改全局变量需要使用 global 关键字(不推荐)。
count = 0 # 全局变量
def increment():
global count
count += 1
increment()
print(count) # 1
Python 特别之处?
Python 中循环变量在循环外可访问的原因
在 Python 中,循环内定义的变量在循环结束后仍然可以访问,这是因为 Python 没有块级作用域(block scope)。
核心原因
Python 的作用域只有以下几种:
- 模块级作用域(全局)
- 函数级作用域
- 类级作用域
而像 for、while、if 等代码块 不会创建新的作用域,因此其中定义的变量仍然属于外层作用域。
示例说明
# 示例 1:for 循环
for i in range(3):
x = i * 2
print(i) # 输出: 2
print(x) # 输出: 4
# 示例 2:if 语句
if True:
y = 100
print(y) # 输出: 100
# 示例 3:while 循环
count = 0
while count < 3:
temp = count
count += 1
print(temp) # 输出: 2
与其他语言对比
# Python
for i in range(3):
pass
print(i) # ✅ 可以访问,输出 2
# Java / C++
for (int i = 0; i < 3; i++) {
// ...
}
// System.out.println(i); // ❌ 编译错误,i 超出作用域
函数内部的情况
即使在函数中,循环变量也属于函数作用域:
def test():
for j in range(3):
value = j
print(j) # ✅ 输出: 2
print(value) # ✅ 输出: 2
test()
# print(j) # ❌ NameError,j 不在全局作用域
注意事项
⚠️ 变量泄露风险
# 可能意外覆盖外部变量
data = [1, 2, 3]
for data in # ❌ 循环变量覆盖了原列表
print(data)
print(data) # 输出: 3,原列表已丢失
⚠️ 闭包中的陷阱
funcs = []
for i in range(3):
funcs.append(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]
最佳实践建议
- 避免在循环中覆盖重要变量名
- 如需限制变量作用域,使用函数封装
- 在闭包中注意变量捕获问题
- 循环后不再使用的变量可显式删除:
del i
总结
| 特性 | Python | Java/C++ |
|---|---|---|
| 循环作用域 | 函数/模块级 | 块级作用域 |
| 循环后可访问 | ✅ 是 | ❌ 否 |
| 设计哲学 | 简洁、灵活 | 严格、安全 |
这是 Python 的设计选择,旨在简化语法,但开发者需注意潜在的作用域问题,编写更健壮的代码。
6. Lambda 函数 (匿名函数)
用于定义简单的、一行的函数。
# 语法: lambda arguments: expression
square = lambda x: x * x
print(square(5)) # 25
# 常见用途:作为参数传给 sort, map, filter
data = [(1, 'd'), (2, 'b'), (4, 'a'), (3, 'c')]
# 按第二个元素排序
data.sort(key=lambda x: x[1])
print(data) # Sort by letter
7. 类型提示 (Type Hints)
Python 3.5+ 引入,虽然不强制,但强烈建议写上。
def calculate_area(width: float, height: float) -> float:
return width * height
本章小结
| 概念 | 说明 |
|---|---|
def |
定义函数 |
return |
返回值,可返回多个 |
| 参数 | 位置参数、关键字参数、默认参数 |
*args |
可变位置参数 (Tuple) |
**kwargs |
可变关键字参数 (Dict) |
lambda |
匿名函数,短小精悍 |
练习题
- 基本函数:编写
max_of_three(a, b, c)函数,返回三个数中的最大值。 - 默认参数:编写
power(x, n=2)函数,计算 x 的 n 次方,默认计算平方。 - 可变参数:编写
sum_all(*args)函数,计算所有传入数字的总和。
下一章:文件操作