Python 使用全局变量,为什么有的时候可以不加 global ?

类使用类方法,访问 success_list 是可以的!

from loguru import logger

success_list: list[float] = [1,2,3,4,5,6,7,8]


class Myclass:
    def run(self):
        logger.debug(success_list)

Myclass().run()

logger.debug(success_list)

运行结果:

2022-07-29 16:15:23.838 | DEBUG    | __main__:run:8 - [1, 2, 3, 4, 5, 6, 7, 8]
2022-07-29 16:15:23.838 | DEBUG    | __main__:<module>:13 - [1, 2, 3, 4, 5, 6, 7, 8]

但是加两行代码就不行了

from loguru import logger

success_list: list[float] = [1,2,3,4,5,6,7,8]


class Myclass:
    def run(self):
        logger.debug(success_list)
        success_list = success_list[1:]
        logger.debug(success_list)

Myclass().run()

logger.debug(success_list)

运行结果:

Traceback (most recent call last):
  File "/Users/ponponon/Desktop/code/me/ideaboom/tools copy.py", line 12, in <module>
    Myclass().run()
  File "/Users/ponponon/Desktop/code/me/ideaboom/tools copy.py", line 8, in run
    logger.debug(success_list)
UnboundLocalError: local variable 'success_list' referenced before assignment
主注意,报错在 logger.debug(success_list) 而不是 success_list = success_list[1:]

但是加上 global 又可以了!?

from loguru import logger

success_list: list[float] = [1,2,3,4,5,6,7,8]


class Myclass:
    def run(self):
        global success_list
        logger.debug(success_list)
        success_list = success_list[1:]
        logger.debug(success_list)

Myclass().run()

logger.debug(success_list)

运行结果:

2022-07-29 16:16:33.181 | DEBUG    | __main__:run:9 - [1, 2, 3, 4, 5, 6, 7, 8]
2022-07-29 16:16:33.181 | DEBUG    | __main__:run:11 - [2, 3, 4, 5, 6, 7, 8]
2022-07-29 16:16:33.181 | DEBUG    | __main__:<module>:15 - [2, 3, 4, 5, 6, 7, 8]

为什么第一份代码可以不加 global ?

阅读 2.7k
3 个回答

当内部作用域想修改外部作用域的变量时,就要用到 global,
如果只是访问的话,可以不用加。

可以考虑用inspect.getclosurevars方法来看一下python对两个函数处理方式的区别。

下面用一个简单的例子连同执行结果说明一下:

>>> import inspect
>>> g = 1
>>> def a():
...     return g
...
>>> def b():
...     g = g + 1
...     return g
...
>>> inspect.getclosurevars(a)
ClosureVars(nonlocals={}, globals={'g': 1}, builtins={}, unbound=set())
>>> inspect.getclosurevars(b)
ClosureVars(nonlocals={}, globals={}, builtins={}, unbound=set())

当遇到一个名字的时候,是从当前开始向外找的。success_lines = .... 是一个 name binding operation ,相当于它会在当前层创建一个 success_lines;这样,如果没有 global ,就找不到外层的了,想用全局的就必须 global 。但是如果没有赋值,那么当前没有这个变量,就可以找到外层的。


resolution of names

4.2.2. Resolution of names
......
When a name is used in a code block, it is resolved using the nearest enclosing scope.
......
If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block.
.....
If the global statement occurs within a block, all uses of the names specified in the statement refer to the bindings of those names in the top-level namespace.

binding of names

Names refer to objects. Names are introduced by name binding operations.

The following constructs bind names:

  • formal parameters to functions,
  • class definitions,
  • function definitions,
  • assignment expressions,
  • ......
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏