在Python编程中,全局变量和局部变量的作用域是一个重要的概念。本文将详细介绍Python中全局变量的使用,以及如何通过global关键字在函数内部修改全局变量。

一、全局变量和局部变量

1. 基本概念

1
2
3
4
5
6
7
8
9
10
11
12
# 全局变量
global_var = 10

def func():
# 局部变量
local_var = 20
print(f"Inside function: global_var = {global_var}")
print(f"Inside function: local_var = {local_var}")

func()
print(f"Outside function: global_var = {global_var}")
# print(local_var) # NameError: name 'local_var' is not defined

2. 作用域规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
x = "global"

def outer():
x = "enclosing"

def inner():
x = "local"
print(f"Inner: x = {x}")

inner()
print(f"Outer: x = {x}")

outer()
print(f"Global: x = {x}")
# 输出:
# Inner: x = local
# Outer: x = enclosing
# Global: x = global

二、global关键字

1. 在函数内部修改全局变量

1
2
3
4
5
6
7
8
9
10
11
counter = 0

def increment():
global counter
counter += 1
return counter

print(increment()) # 输出:1
print(counter) # 输出:1
print(increment()) # 输出:2
print(counter) # 输出:2

2. global与局部变量的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 没有global关键字
x = 10

def func_without_global():
x = 20 # 创建新的局部变量,不影响全局变量
return x

print(func_without_global()) # 输出:20
print(x) # 输出:10(全局变量未改变)

# 有global关键字
def func_with_global():
global x
x = 20 # 修改全局变量
return x

print(func_with_global()) # 输出:20
print(x) # 输出:20(全局变量被改变)

3. 在同一函数中声明多个全局变量

1
2
3
4
5
6
7
8
9
10
count = 0
name = "original"

def update():
global count, name
count += 1
name = "updated"

update()
print(f"count = {count}, name = {name}") # 输出:count = 1, name = updated

三、全局变量的最佳实践

1. 尽量避免使用全局变量

1
2
3
4
5
6
7
8
9
10
11
12
13
# 不推荐:使用全局变量
total = 0

def add_to_total(value):
global total
total += value

# 推荐:使用参数和返回值
def add_to_total_good(value, total=0):
return total + value

total = add_to_total_good(10, 0)
total = add_to_total_good(20, total)

2. 使用类或模块封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 使用类封装相关状态
class Counter:
def __init__(self):
self._count = 0

def increment(self):
self._count += 1

@property
def count(self):
return self._count

counter = Counter()
counter.increment()
counter.increment()
print(counter.count) # 输出:2

3. 使用函数闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
def create_counter():
count = 0

def increment():
nonlocal count
count += 1
return count

return increment

counter = create_counter()
print(counter()) # 输出:1
print(counter()) # 输出:2

四、nonlocal关键字

1. 基本用法

nonlocal用于在嵌套函数中修改外层函数的变量:

1
2
3
4
5
6
7
8
9
10
11
def outer():
x = 10

def inner():
nonlocal x
x = 20

inner()
print(f"Outer: x = {x}") # 输出:Outer: x = 20

outer()

2. global vs nonlocal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# global:作用于全局变量
x = "global"

def func1():
global x
x = "modified global"

# nonlocal:作用于外层函数的变量
def outer():
x = "enclosing"

def inner():
nonlocal x
x = "modified enclosing"

inner()
print(f"Inside outer: x = {x}") # 输出:Inside outer: x = modified enclosing

func1()
print(f"Global: x = {x}") # 输出:Global: x = modified global
outer()

五、综合示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
全局变量综合示例
"""

# 示例1:配置管理器(使用类而非全局变量)
class Config:
_instance = None
_config = {}

def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance

def set(self, key, value):
self._config[key] = value

def get(self, key, default=None):
return self._config.get(key, default)

config1 = Config()
config2 = Config()

config1.set("debug", True)
print(config2.get("debug")) # 输出:True(单例模式)
print(config1 is config2) # 输出:True

# 示例2:使用函数闭包替代全局变量
def create_logger():
logs = []

def log(message):
logs.append(message)
return logs

return log

logger = create_logger()
logger("Message 1")
logger("Message 2")
print(logger([])) # 输出:['Message 1', 'Message 2']

# 示例3:状态机
class StateMachine:
def __init__(self):
self._state = "idle"
self._transitions = {
"idle": {"start": "running"},
"running": {"stop": "idle", "pause": "paused"},
"paused": {"resume": "running", "stop": "idle"}
}

def transition(self, action):
if action in self._transitions.get(self._state, {}):
self._state = self._transitions[self._state][action]
return True
return False

@property
def state(self):
return self._state

sm = StateMachine()
print(sm.state) # 输出:idle
sm.transition("start")
print(sm.state) # 输出:running
sm.transition("pause")
print(sm.state) # 输出:paused

六、注意事项

1. 全局变量的线程安全性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import threading

# 全局变量在多线程环境下不安全
counter = 0

def increment_ntimes(n):
for _ in range(n):
global counter
counter += 1

# 创建两个线程同时修改全局变量
t1 = threading.Thread(target=increment_ntimes, args=(100000,))
t2 = threading.Thread(target=increment_ntimes, args=(100000,))

t1.start()
t2.start()
t1.join()
t2.join()

print(counter) # 可能不是200000(存在竞态条件)

2. 模块级全局变量

1
2
3
4
5
6
7
# mymodule.py
# module_level_var = "initial"

# main.py
# import mymodule
# print(mymodule.module_level_var) # 输出:initial
# mymodule.module_level_var = "modified" # 可以修改模块级变量

3. 调试全局变量问题

1
2
3
4
5
6
7
8
9
10
# 使用globals()查看所有全局变量
x = 10
y = "hello"

def show_globals():
for key, value in globals().items():
if not key.startswith('_'):
print(f"{key}: {value}")

show_globals()