PYTHON基础技能 – 一文搞懂Python局部变量与全局变量的12大陷阱

释放双眼,带上耳机,听听看~!

今天我们要来聊聊一个让人又爱又恨的话题——局部变量与全局变量的八大迷雾。在Python的世界里,变量就像是你的小宠物,有时候它们乖乖听话,但一不小心就给你挖了个大坑!别担心,今天我们就一起把这些陷阱挖出来,填平它,让你的编程之路畅通无阻!

1. 基础篇:什么是局部和全局变量?

想象你在厨房做饭,

1
ingredient

(食材)是全局的,因为整个厨房都能用到它。而当你在切洋葱时,那把刀(

1
knife

)就是局部的,只在这个特定任务(函数)里使用。


1
ingredient&nbsp;=&nbsp;"洋葱"<br><br>def&nbsp;chop():<br>&nbsp;&nbsp;&nbsp;&nbsp;knife&nbsp;=&nbsp;"锋利的菜刀"<br>&nbsp;&nbsp;&nbsp;&nbsp;print(f"用{knife}切{ingredient}")<br><br>chop()

这里,

1
knife

仅在

1
chop

函数内部可见,就是局部变量,而

1
ingredient

是全局变量,哪里都能访问。

2. 修改全局变量的第一坑:你以为你能改?

直接在函数里修改全局变量?Python可不轻易让你得逞!


1
global_var&nbsp;=&nbsp;10<br><br>def&nbsp;change_global():<br>&nbsp;&nbsp;&nbsp;&nbsp;global_var&nbsp;=&nbsp;20&nbsp;<em>#&nbsp;注意,这只是创建了一个新的局部变量!</em><br><br>change_global()<br>print(global_var)&nbsp;<em>#&nbsp;猜猜看,输出是多少?</em>

输出还是10!Python说:“嘿,你这是新建了个局部的

1
global_var

,原来的我可没动哦。”

3. 正确修改全局变量:要用
1
global

关键字!

想动我的全局变量?得先打招呼!


1
global_var&nbsp;=&nbsp;10<br><br>def&nbsp;change_global_correctly():<br>&nbsp;&nbsp;&nbsp;&nbsp;global&nbsp;global_var<br>&nbsp;&nbsp;&nbsp;&nbsp;global_var&nbsp;=&nbsp;20<br><br>change_global_correctly()<br>print(global_var)&nbsp;<em>#&nbsp;这次对了吧?</em>

这次,输出是20,因为我们明确告诉Python:“嘿,我要动的是全局的那个家伙。”

4. 局部变量的“幽灵”效应

当你在函数内未声明就使用变量名,Python会认为你在找全局变量,但这可能会引发一些诡异的现象。


1
def&nbsp;mystery():<br>&nbsp;&nbsp;&nbsp;&nbsp;print(unknown_var)&nbsp;<em>#&nbsp;啊哦,这是谁?</em><br><br>try:<br>&nbsp;&nbsp;&nbsp;&nbsp;mystery()<br>except&nbsp;NameError&nbsp;as&nbsp;e:<br>&nbsp;&nbsp;&nbsp;&nbsp;print(e)&nbsp;<em>#&nbsp;未知变量错误,它真的存在吗?</em>

这会抛出NameError,提醒你“unknown_var”这个幽灵并不存在于全局空间。

5. 非直观的变量作用域:嵌套函数

嵌套函数可以访问外层函数的变量,但修改时要小心!


1
def&nbsp;outer():<br>&nbsp;&nbsp;&nbsp;&nbsp;outer_var&nbsp;=&nbsp;"外层的宝藏"<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;inner():<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(outer_var)&nbsp;<em>#&nbsp;能找到我外公的宝藏吗?</em><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outer_var&nbsp;=&nbsp;"被内层修改了"&nbsp;<em>#&nbsp;实际上,这创造了一个新的局部变量</em><br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;inner()<br>&nbsp;&nbsp;&nbsp;&nbsp;print(outer_var)&nbsp;<em>#&nbsp;外层的值会变吗?</em><br><br>outer()&nbsp;<em>#&nbsp;来看看结果</em>

你会发现,外层的值没变,因为内层创建了一个同名的局部变量。

6. 使用
1
nonlocal

关键字的场景

当你确实想在嵌套函数中修改外层函数的变量时,

1
nonlocal

来帮忙!


1
def&nbsp;outer():<br>&nbsp;&nbsp;&nbsp;&nbsp;outer_var&nbsp;=&nbsp;"原始宝藏"<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;inner():<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nonlocal&nbsp;outer_var<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outer_var&nbsp;=&nbsp;"宝藏升级了"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(outer_var)<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;inner()<br>&nbsp;&nbsp;&nbsp;&nbsp;print(outer_var)&nbsp;<em>#&nbsp;这次会怎样?</em><br><br>outer()&nbsp;<em>#&nbsp;哈哈,成功修改!</em>

1
nonlocal

关键字让Python知道你想修改的是外层的变量,不是创建新的。

7. 全局变量的滥用:是福还是祸?

全局变量用得爽,但过度依赖就像吃太多糖,短期内甜,长期有害。它可能导致代码难以维护和测试。尽量通过函数参数和返回值传递数据,保持模块间的独立性,这样你的代码才会更健康!

8. 小心闭包的陷阱

闭包是Python中的高级特性,但也可能因变量作用域而让人困惑。


1
def&nbsp;create_counter():<br>&nbsp;&nbsp;&nbsp;&nbsp;count&nbsp;=&nbsp;0<br>&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;counter():<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nonlocal&nbsp;count<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count&nbsp;+=&nbsp;1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;count<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;counter<br><br>my_counter&nbsp;=&nbsp;create_counter()<br>print(my_counter())&nbsp;<em>#&nbsp;1</em><br>print(my_counter())&nbsp;<em>#&nbsp;2</em><br><em>#&nbsp;看,count被正确地保留和增加了!</em>

闭包可以记住外部函数的状态,但记得,这也意味着它可能会保留比预期更多的内存,所以使用时要谨慎。


高级技巧

9. 利用模块级别的变量

在大型项目中,有时需要在整个模块范围内共享数据。你可以定义模块级别的变量来实现这一目的。但请记住,这样做可能会增加模块间的耦合度,要谨慎使用。


1
<em>#&nbsp;my_module.py</em><br>shared_data&nbsp;=&nbsp;&#091;]<br><br>def&nbsp;add_to_shared(data):<br>&nbsp;&nbsp;&nbsp;&nbsp;shared_data.append(data)<br><br>def&nbsp;get_shared():<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;shared_data<br><br><em>#&nbsp;另一个文件中使用</em><br>import&nbsp;my_module<br><br>my_module.add_to_shared("Hello")<br>print(my_module.get_shared())&nbsp;<em>#&nbsp;输出:&nbsp;&#091;'Hello']</em>

10. 全局变量的替代方案:配置文件与环境变量

在处理配置信息或应用设置时,使用配置文件(如

1
.ini

,

1
.json

, 或环境变量)是一个更好的选择,而不是硬编码全局变量。这样可以提高代码的灵活性和可维护性。


1
<em>#&nbsp;假设有一个config.json</em><br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;"database":&nbsp;"my_db",<br>&nbsp;&nbsp;&nbsp;&nbsp;"port":&nbsp;5432<br>}<br><br>import&nbsp;json<br>import&nbsp;os<br><br><em>#&nbsp;读取配置文件</em><br>with&nbsp;open('config.json')&nbsp;as&nbsp;f:<br>&nbsp;&nbsp;&nbsp;&nbsp;config&nbsp;=&nbsp;json.load(f)<br><br><em>#&nbsp;或者使用环境变量</em><br>DB_NAME&nbsp;=&nbsp;os.getenv('DB_NAME',&nbsp;'default_db')&nbsp;<em>#&nbsp;如果环境变量不存在,则使用'default_db'</em>

11. 上下文管理器与
1
with

语句

虽然这不是直接关于变量作用域的,但了解上下文管理器可以帮助你更好地管理资源,比如文件操作时的自动关闭。


1
with&nbsp;open('myfile.txt',&nbsp;'w')&nbsp;as&nbsp;file:<br>&nbsp;&nbsp;&nbsp;&nbsp;file.write("Hello,&nbsp;world!")<br><em>#&nbsp;文件在这里自动关闭,无需显式调用file.close()</em>

这里的

1
file

变量在

1
with

块内有效,一旦执行完毕,Python会确保资源得到释放。

12. 闭包的高级应用:记忆化

记忆化是一种优化技术,用于存储函数计算的中间结果,减少重复计算。这对于有重叠子问题的递归函数尤其有用。


1
def&nbsp;memoize(func):<br>&nbsp;&nbsp;&nbsp;&nbsp;cache&nbsp;=&nbsp;{}<br>&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;wrapper(*args):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;args&nbsp;not&nbsp;in&nbsp;cache:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache&#091;args]&nbsp;=&nbsp;func(*args)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;cache&#091;args]<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;wrapper<br><br>@memoize<br>def&nbsp;fibonacci(n):<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;n&nbsp;&lt;=&nbsp;1:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;n<br>&nbsp;&nbsp;&nbsp;&nbsp;else:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;fibonacci(n-1)&nbsp;+&nbsp;fibonacci(n-2)<br><br>print(fibonacci(10))&nbsp;<em>#&nbsp;55,而且只计算了一次n=1到n=10</em>

通过这种方式,

1
memoize

装饰器创建了一个闭包,它记录了函数调用的结果,避免了重复劳动。

给TA打赏
共{{data.count}}人
人已打赏
安全运维

安全运维之道:发现、解决问题的有效闭环

2024-4-14 20:59:36

安全运维

稳定性建设 – 架构优化的关键策略

2025-2-11 17:15:56

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索