函数局部变量与全局变量
基本概念
局部变量:在函数内部定义的变量,仅在该函数内部有效,函数执行结束后自动销毁。
全局变量:在函数外部定义,作用于整个程序(模块)范围内的变量。可以被函数内部访问,但修改需特别处理。
局部变量管自己,全局变量管大家;函数想改全局时,记得加 global。
语法格式
- 全局变量定义
python
# 全局变量
# 在函数外定义
name = "Alice" # 全局变量
age = 25
def greet():
print(f"Hello, {name}") # 可以读取全局变量
- 局部变量定义
python
# 函数内定义
def calculate_area(radius):
pi = 3.14159 # 局部变量,仅函数内有效
area = pi * radius ** 2
return area # 返回局部变量的计算结果
全局变量与局部变量对比
| 方面 | 全局变量 | 局部变量 |
|---|---|---|
| 定义位置 | 函数外 | 函数内 |
| 作用域 | 整个模块 | 函数内部 |
| 生命周期 | 程序运行期间 | 函数调用期间 |
| 修改方式 | 需要用 global 声明 |
直接赋值即可 |
| 是否能修改 | 不能直接修改(除非声明 global) | 可以自由修改 |
| 是否共享 | 是(多个函数共享) | 否(仅本函数独占) |
| 是否冲突 | 与局部同名时会被局部屏蔽 | 可与全局同名,局部优先 |
| 推荐使用 | 少量常量(如 MAX_SIZE) | 大多数变量处理 |
locals()、globals()和nonlocal 变量
1、locals() ------ 当前作用域的局部变量字典
- 返回一个字典,包含当前函数/模块中所有局部变量名和它们的当前值。
- 仅在函数内有效,模块顶层调用也返回全局变量(见下方说明)。
python
# 函数内部查看所有局部变量
def calculate_area(radius, height):
pi = 3.14159
area = pi * radius ** 2
volume = area * height
print("当前局部变量:")
for k, v in locals().items():
print(f" {k} = {v}")
return volume
calculate_area(5, 10)
2、globals() ------ 全局作用域的变量字典
-
返回一个字典,包含当前模块中所有全局变量(包括函数、类、变量)。
-
可用于读取或修改全局变量。
python
# 动态修改全局变量
counter = 0
name = "Default"
def update_global_var(var_name, value):
if var_name in globals():
globals()[var_name] = value
print(f"✅ 已更新全局变量 {var_name} = {value}")
else:
print(f"❌ 变量 {var_name} 不存在于全局作用域")
update_global_var("counter", 100)
update_global_var("name", "Bob")
print(globals()["counter"]) # 输出:100
3、nonlocal ------ 闭包中引用并修改外层函数的局部变量
-
声明一个变量不是局部变量,也不是全局变量,而是位于外层嵌套函数的作用域中。
-
用于修改闭包中外部函数的局部变量。
python
# 防止误改全局变量
# nonlocal 只影响外层函数,不会误改全局!
count = 1000 # 全局变量
def outer():
count = 10 # 外层局部变量
def inner():
nonlocal count # 指向 outer 的 count
count += 1
print(f"inner: count = {count}")
return inner
inner_func = outer()
inner_func() # 输出:inner: count = 11
print(f"全局 count: {count}") # 输出:global count: 1000(未被影响)
综合举例
python
# 展示局部变量、全局变量、locals()、globals()、global、nonlocal 的协同应用
# 全局变量(模块级)
counter = 100 # 全局变量
name = "Global" # 全局变量
debug_mode = True # 全局配置
print("🚀 程序开始:全局变量初始状态")
print(f"全局 counter = {counter}, name = {name}, debug_mode = {debug_mode}")
# ----------------------------
# 1️⃣ 函数:普通函数,仅读取全局变量
# ----------------------------
def greet_user():
print("\n--- 1. 普通函数调用 ---")
greeting = "Hello" # 局部变量
print(f"greeting (局部) = {greeting}")
print(f"读取全局变量 name = {name}")
print("locals() 中变量:")
for k, v in locals().items():
print(f" {k} => {v}")
greet_user()
# ----------------------------
# 2️⃣ 函数:使用 global 修改全局变量
# ----------------------------
def update_counter():
global counter # 声明使用全局变量
print("\n--- 2. 使用 global 修改全局变量 ---")
print(f"调用前 counter = {counter}")
counter = counter + 10
print(f"调用后 counter = {counter}")
print("通过 globals() 查看修改结果:")
print(f"globals()['counter'] = {globals()['counter']}")
update_counter()
# ----------------------------
# 3️⃣ 闭包函数:使用 nonlocal 修改外层函数变量
# ----------------------------
def make_counter():
count = 0 # 外层函数的局部变量(非全局)
print(f"\n--- 3. 闭包函数:使用 nonlocal ---")
print(f"初始化:count = {count}")
def increment():
nonlocal count # 指向 make_counter 中的 count
count += 1
print(f"increment 中 count = {count}")
print("使用 locals() 查看内部局部变量:")
print(f" locals() -> {locals()}")
def get_count():
return count
return increment, get_count
# 创建计数器实例
inc, get = make_counter()
print("\n调用计数器:")
inc() # count=1
inc() # count=2
print(f"当前 count = {get()}") # 输出:2
# ----------------------------
# 4️⃣ 模块级:动态修改全局变量(演示 globals() 实用性)
# ----------------------------
def set_config(key, value):
print("\n--- 4. 动态设置配置(使用 globals())---")
if key in globals():
print(f"修改全局变量 {key} 从 {globals()[key]} 到 {value}")
globals()[key] = value
print(f"已更新: {key} = {globals()[key]}")
else:
print(f"变量 {key} 不存在,跳过")
set_config("debug_mode", False) # 修改全局配置
print(f"最新 debug_mode = {debug_mode}")
# ----------------------------
# 5️⃣ 最后总结:输出所有变量状态
# ----------------------------
print("\n✅ 程序结束:最终状态")
print(f"全局变量 counter = {counter}")
print(f"全局变量 debug_mode = {debug_mode}")
print(f"全局变量 name = {name}")
print(f" locals() 在模块顶层 = {locals()}") # 等价于 globals()
匿名函数lambda
lambda 函数是一种小型的匿名函数,使用 lambda 关键字定义。它可以在一行内定义一个简单的函数,无需使用 def 关键字和函数名。
语法格式:
注意事项:只能有一个表达式,不能包含语句(如 print, return)
python
# 语法格式
lambda arg1[, arg2, arg3,...,argn]:expression
"""
说明
lambda:关键字,表示定义匿名函数
arg1:参数,可以有多个参数,用逗号分隔,也可以没有参数
::冒号分隔参数和表达式
expression:表达式,函数的返回值(只能有一个表达式,不能有多行代码、不能包含语句(如 print, return))
"""
基本应用
匿名函数一般用在不需要函数名称的场合,如一些高阶函数的部分参数是函数,这很适合使用匿名函数。
python
# 基本应用 1:基础 lambda 函数 - 两数相加
add_lambda = lambda x, y: x + y
print(f"\n【示例 1】两数相加:5 + 3 = {add_lambda(5, 3)}")
# 基本应用 2:带默认参数的 lambda 函数
power = lambda x, n=2: x ** n
print(f"\n【示例 2】幂次方计算:")
print(f" 5 的平方 = {power(5)}")
print(f" 2 的 4 次方 = {power(2, 4)}")
# 基本应用 3:多参数 lambda 函数
sum_three = lambda a, b, c: a + b + c
print(f"\n【示例 3】三数求和:10 + 20 + 30 = {sum_three(10, 20, 30)}")
# 基本应用 4:return返回值是匿名函数
def func(b):
return lambda x: 2 * x + b
print(func(5)(10)) # 输出:25
linear1 = func(5) # 5 将传给lambda 函数的 b
print(linear1(10)) # 10是lambda 函数的 x 输出:25
linear2 = func(3)
print(linear2(10)) # 输出:23
# 匿名函数作为高阶函数的参数
def my_car(cars,func):
for car in cars:
print(func(car))
dream_cars = ['bmw', 'audi', 'toyota', 'subaru']
my_car(dream_cars,lambda carbrand:"My dream car is " + carbrand.title())
lambda 与 filter()、map()、reduce()、sorted() 的联合应用
1、**lambda + filter()**函数
python
# 语法格式
"""
filter(function, iterable)
或
filter(lambda 参数:条件表达式,可迭代对象)
说明:
filter() 用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新迭代器
function:判断函数,返回 True 或 False
iterable:可迭代对象(列表、元组等)
"""
# 应用示例
# 筛选特定类型文件
files = [
{'name': 'report.pdf', 'type': 'pdf'},
{'name': 'image.jpg', 'type': 'jpg'},
{'name': 'data.csv', 'type': 'csv'},
{'name': 'doc.pdf', 'type': 'pdf'},
{'name': 'photo.png', 'type': 'png'}
]
pdf_files = list(filter(lambda f: f['type'] == 'pdf', files))
print(f"PDF 文件:{[f['name'] for f in pdf_files]}")
2、**lambda + map()**函数
python
# 语法格式
"""
map(function, iterable, ...)
或
map(lambda 参数:表达式,可迭代对象)
说明:
map() 对可迭代对象的每个元素应用函数,返回处理结果
function:要对可迭代对象中每个元素应用的函数
iterable:一个或多个可迭代对象
返回处理后的新迭代器
"""
# 案例
# 字符串大写
words = ["hello", "world", "python"]
upper_words = list(map(lambda x: x.upper(), words))
print(f"大写:{upper_words}") # ['HELLO', 'WORLD', 'PYTHON']
# 多列表对应元素相加
words = ["hello", "world", "python"]
upper_words = list(map(lambda x: x.upper(), words))
print(f"大写:{upper_words}") # ['HELLO', 'WORLD', 'PYTHON']
# 提取用户邮箱列表
users = [
{'name': '张三', 'email': 'zhangsan@example.com', 'age': 25},
{'name': '李四', 'email': 'lisi@example.com', 'age': 30},
{'name': '王五', 'email': 'wangwu@example.com', 'age': 28}
]
emails = list(map(lambda u: u['email'], users))
print(f"邮箱列表:{emails}")
3、**lambda + reduce()**函数
python
# 语法格式
"""
from functools import reduce
reduce(function, iterable[, initializer])
# 或
reduce(lambda 参数 1, 参数 2: 表达式,可迭代对象 [, 初始值])
说明:
reduce() 会对参数序列中元素进行累积操作
function:接收两个参数的函数
iterable:可迭代对象
initializer:可选的初始值
"""
# 示例
# 求和
from functools import reduce
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
print(f"乘积:{product}") # 120
# 查找最高分学生
rom functools import reduce
students = [
{'name': '张三', 'score': 85},
{'name': '李四', 'score': 92},
{'name': '王五', 'score': 78},
{'name': '赵六', 'score': 95}
]
top_student = reduce(lambda x, y: x if x['score'] > y['score'] else y, students)
print(f"最高分学生:{top_student['name']} - {top_student['score']}分")
4、**lambda + sorted()**函数
python
# 语法格式
"""
sorted(iterable, key=lambda 参数:表达式,reverse=False/True)
含义和作用:
sorted() 对所有可迭代的对象进行排序操作
iterable:可迭代对象
key:指定用元素的哪个属性或索引进行排序
reverse:排序规则,False 为升序(默认),True 为降序
返回新的已排序列表
"""
# 数字升序排序
numbers = [5, 2, 8, 1, 9, 3]
sorted_numbers = sorted(numbers, key=lambda x: x)
print(f"升序:{sorted_numbers}") # [1, 2, 3, 5, 8, 9]
# 商品按价格和销量排序
products = [
{'name': '商品 A', 'price': 100, 'sales': 500},
{'name': '商品 B', 'price': 50, 'sales': 800},
{'name': '商品 C', 'price': 100, 'sales': 300},
{'name': '商品 D', 'price': 80, 'sales': 600}
]
# 按价格升序,价格相同时按销量降序
sorted_products = sorted(products, key=lambda x: (x['price'], -x['sales']))
print("商品排序(价格升序,销量降序):")
for p in sorted_products:
print(f" {p['name']}: ¥{p['price']}, 销量:{p['sales']}")
pass与函数
pass 是 Python 中的一个空语句(null statement),它什么也不做,但具有明确的语法意义。在函数中使用 **pass**有其特定的用途和注意事项。
- 占位符作用:临时留空函数体
当你正在设计函数结构,但还没想到具体实现时,可以用 pass 占位,避免语法错误。
python
def create_database_table():
"""创建数据库表结构(暂未实现)"""
pass # TODO: 根据模型生成 SQL
- 防止
IndentationError
在 Python 中,函数体不能为空(与 C/Java 不同),必须有缩进的代码块。如果写成下面这样会报错:
python
# 报错:IndentationError: expected an indented block
def my_func():
# 没有代码,会报错!
type关键字应用在函数
type关键字的作用:列出数据的数据类型
python
# type关键字在函数中应用
def fun(arg):
pass
print("列出函数fun的type类型: ", type(fun)) # <class 'function'>
print("列出匿名函数lambda的type类型: ", type(lambda x: x)) # <class 'function'>
print("列出内置函数abs的type类型: ", type(abs)) # <class 'builtin_function_or_method'>
设计自己的range()
我们可以模仿内置 range() 的行为,实现一个自定义版本。
- 支持 start, stop, step 参数;
- 返回类似 range 的可迭代对象(使用 yield 实现生成器);
- 支持正序、倒序、负步长
python
# 设计一个my_range()函数
def my_range(start, stop=None, step=1):
"""
模拟内置 range() 函数行为。
参数:
start: 起始值 (若无 stop,则作为 stop,start 默认为 0)
stop: 结束值(不包含)
step: 步长,默认为 1
返回:生成器对象
"""
# 处理只有 1 个参数的情况:range(5) -> start=5, stop=None
if stop is None:
stop = start
start = 0
# 步长不能为 0
if step == 0:
raise ValueError("step argument must not be zero")
# 根据步长决定迭代方向
if step > 0:
# 正序:从 start 开始,直到小于 stop
while start < stop:
yield start
start += step
else:
# 倒序:从 start 开始,直到大于 stop
while start > stop:
yield start
start += step
# 测试自定义 my_range
print(list(my_range(5))) # [0, 1, 2, 3, 4]
yield关键字作用及工作原理
yield作用:用来定义一个生成器函数(generator function)------它能"暂停"执行并返回一个值,下次调用时从暂停处继续运行。
yield工作原理,当你调用一个使用了 yield 的函数时:
- 函数不会立即运行;
- Python 返回一个 生成器对象;
- 每次调用 next(generator) 或用 for 循环遍历时,函数从上次 yield 位置恢复执行;
- 执行到下一个 yield 时再次暂停,返回值;
- 直到函数结束或 return,抛出 StopIteration 异常。
yield注意事项
| 技巧 | 说明 |
|---|---|
| ✅ 生成器是"懒加载" | 只有在 next() 或 for 循环时才执行 |
| ✅ 不能重复使用已耗尽的生成器 | 一旦遍历完,就不能再用了 |
✅ 可以用 list(gen) 转为列表 |
但会失去"内存节约"优势 |
✅ 支持 send()、throw()(协程) |
高级用法,用于交互式生成 |
❌ 不能对生成器用 len() |
因为它可能是无限的 |
yield与return对比
| 比较项 | return |
yield |
|---|---|---|
| 是否暂停 | 否 | 是 |
| 是否可以多次用 | 否 | 是(多次调用 next()) |
| 内存使用 | 高(需保存全部结果) | 低(按需生成) |
| 函数返回类型 | 普通值 | 生成器对象 |
| 是否适合大数/无限序列 | 否 | ✔️ 是 |
python
# return不能批量输出
def get_numbers():
for i in range(5):
return i # 仅返回第一个值,循环不会继续
print(get_numbers()) # 输出:0
# yield 生成器对象 批量输出
def get_numbers():
for i in range(5):
yield i # 暂停并返回 i,下次调用继续
nums = get_numbers() # 返回生成器对象,不执行函数体!
print(nums) # <generator object get_numbers at ...>
# 逐个获取值
print(next(nums)) # 0
print(next(nums)) # 1
print(next(nums)) # 2
装饰器
装饰器(Decorator) 是 Python 中一种高阶函数,用于在不对原函数代码做修改的前提下,动态地为函数添加额外功能。
它本质是:一个接收函数作为参数,并返回一个新函数的函数。
基本语法(使用 @ 语法糖)
python
# 装饰器语法格式
@decorator_name
def function_name():
# 函数逻辑
pass
等价于:
def function_name():
# 函数逻辑
pass
function_name = decorator_name(function_name)
装饰器核心结构(原理)
python
"""
说明:
• func:被装饰的原始函数。
• wrapper:包装函数,负责执行额外逻辑 + 调用原函数。
• *args, **kwargs:支持任意参数传递,提升通用性。
"""
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!
# 函数执行后的操作