python局部变量与全局变量

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

想象你在厨房做饭,ingredient(食材)是全局的,因为整个厨房都能用到它。而当你在切洋葱时,那把刀(knife)就是局部的,只在这个特定任务(函数)里使用。

ingredient = "洋葱"

def chop():
    knife = "锋利的菜刀"
    print(f"用{knife}切{ingredient}")

chop()

 这里,knife仅在chop函数内部可见,就是局部变量,而ingredient是全局变量,哪里都能访问。

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

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

global_var = 10

def change_global():
    global_var = 20 # 注意,这只是创建了一个新的局部变量!

change_global()
print(global_var) # 猜猜看,输出是多少?

输出还是10!Python说:“嘿,你这是新建了个局部的global_var,原来的我可没动哦。”

3. 正确修改全局变量:要用global关键字!

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

global_var = 10

def change_global_correctly():
    global global_var
    global_var = 20

change_global_correctly()
print(global_var) # 这次对了吧?

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

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

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

def mystery():
    print(unknown_var) # 啊哦,这是谁?

try:
    mystery()
except NameError as e:
    print(e) # 未知变量错误,它真的存在吗?

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

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

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

def outer():
    outer_var = "外层的宝藏"
    
    def inner():
        print(outer_var) # 能找到我外公的宝藏吗?
        outer_var = "被内层修改了" # 实际上,这创造了一个新的局部变量
    
    inner()
    print(outer_var) # 外层的值会变吗?

outer() # 来看看结果

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

6. 使用nonlocal关键字的场景

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

def outer():
    outer_var = "原始宝藏"
    
    def inner():
        nonlocal outer_var
        outer_var = "宝藏升级了"
        print(outer_var)
    
    inner()
    print(outer_var) # 这次会怎样?

outer() # 哈哈,成功修改!

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

7. 小心闭包的陷阱

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

def create_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

my_counter = create_counter()
print(my_counter()) # 1
print(my_counter()) # 2
# 看,count被正确地保留和增加了!

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

8. 利用模块级别的变量

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

# my_module.py
shared_data = []

def add_to_shared(data):
    shared_data.append(data)

def get_shared():
    return shared_data

# 另一个文件中使用
import my_module

my_module.add_to_shared("Hello")
print(my_module.get_shared()) # 输出: ['Hello']

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

在处理配置信息或应用设置时,使用配置文件(如.ini.json, 或环境变量)是一个更好的选择,而不是硬编码全局变量。这样可以提高代码的灵活性和可维护性。

# 假设有一个config.json
{
    "database": "my_db",
    "port": 5432
}

import json
import os

# 读取配置文件
with open('config.json') as f:
    config = json.load(f)

# 或者使用环境变量
DB_NAME = os.getenv('DB_NAME', 'default_db') # 如果环境变量不存在,则使用'default_db'

10. 上下文管理器与with语句

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

with open('myfile.txt', 'w') as file:
    file.write("Hello, world!")
# 文件在这里自动关闭,无需显式调用file.close()

这里的file变量在with块内有效,一旦执行完毕,Python会确保资源得到释放。

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

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

def memoize(func):
    cache = {}
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper

@memoize
def fibonacci(n):
    if n <= 1:
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10)) # 55,而且只计算了一次n=1到n=10

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

附加:下面举例全局变量与局部变量

####全局变量变量名大写
####局部变量变量名小写
# 如果函数的内容无global关键字,优先读取局部变量,能读取全局变量,无法对全局变量重新赋值 NAME='fff'
# 但是对于可变类型,可以对内部元素进行操作
# 如果函数中有global关键字,变量本质上就是全局的哪个变量,可读取可赋值, NAME='fff'
NAME = ["哈哈","拉拉"]

def test():
    global NAME
    NAME.append("添加")
    print("你好",NAME)

test()

#错误示例
# 以下这个不知道找哪个变量了
NAME = ["哈哈","拉拉"]

def test1():
    NAME.append("添加")
    global NAME
    print("你好",NAME)

test1()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值