global关键字怎么在python中使用

这期内容当中小编将会给大家带来有关global关键字怎么在python中使用,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

摘要

global关键字怎么在python中使用

  • global标志实际上是为了提示 python 解释器,表明被其修饰的变量是全局变量。这样解释器就可以从当前空间 (current scope) 中读写相应变量了。

  • Python 的全局变量是模块 (module) 级别的

  • 每个 python 函数拥有对应的__globals__字典,该字典与函数所属模块的__dict__字典完全相同。函数的全局变量也会从这个字典中获取

  • 注:上面三句话的意思就是,python 解释器发现函数中的某个变量被global关键字修饰,就去函数的__globals__字典变量中寻找(因为 python 中函数也是一等对象);同时,一个模块中每个函数的__globals__字典变量都是模块__dict__字典变量的引用,二者值完全相同。

  • 避免全局变量将使得程序更容易被调试,同时也能提升程序的可读性

  • 使用到的全局变量只是作为引用,不在函数中修改它的值的话,不需要加global关键字.使用到的全局变量,需要在函数中修改的话,就涉及到歧义问题. 因此在函数中修改全局变量的话需要加global关键字

动机

我最近遇到了一个关于 python 全局变量的问题,如下面这个简单例子里展示(当然实际代码要比这个复杂的多,这里只是一个抽象出来当例子)。例子中foo.py定义了函数f,而函数f调用了全局变量a:

#foo.py

deff():
print(a)

defmain():
globala
a=5
f()

if__name__=='__main__':
main()

运行上面这个文件将如预料中的输出5。在另一个文件bar.py中我们引入上面的f,代码如下

#bar.py
fromfooimportf

defmain():
f()

main()

运行bar.py将报NameError错误。这是因为a被定义在foo.py的main函数中,而当导入f函数时,foo.py的main函数并未被运行,所以a也没哟被定义。

Traceback(mostrecentcalllast):
File"bar.py",line10,in<module>
main()
File"bar.py",line7,inmain
f()
File"foo.py",line5,inf
print(a)
NameError:globalname'a'isnotdefined

定义全局变量a

为了修复上面当问题第一反应是在bar.py中定义全局变量a,这样f就可以找到变量a了,如下面的代码:

#bar.py
fromfooimportf

defmain():
globala
a=4
f()

main()

然而依旧会报错,黑人问号脸???

Traceback(mostrecentcalllast):
File"/tmp/example/bar.py",line13,in<module>
main()
File"/tmp/example/bar.py",line9,inmain
f()
File"/tmp/example/foo.py",line5,inf
print(a)
NameError:globalname'a'isnotdefined

函数的__globals__属性与 python 的global语句

python 的global语句的作用只是提示 python 解释器,被global修饰的变量是一个全局变量,利用上面例子里函数f的反编译代码可以清除的看到这一点:

importdis
fromfooimportf

dis.dis(f)
50LOAD_GLOBAL0(print)
2LOAD_GLOBAL1(a)
4CALL_FUNCTION1
6POP_TOP
8LOAD_CONST0(None)
10RETURN_VALUE

面可以看出变量a被认为是全局变量。Python 中的每一个函数都拥有一个__globals__字典变量,该变量实际是函数所属模块的__dict__变量的引用。所以在bar.py中我们想在bar.main函数中将全局变量a赋值为4,实际改变的是bar.py的__dict__字典变量 (注:而不是定义f的foo.py的__dict__字典变量)

#bar.py
defmain():
globala
a=4
print(main.__globals__.keys())
print(main.__globals__['a'])
dict_keys(['__name__','__doc__','__package__','__loader__','__spec__','__annotations__','__builtins__','__file__','__cached__','foo','f','dis','main','a'])
4

上面的代码输出了main.__globals__(即bar.__dict__) 中全局变量a的值是4,然而这个值对函数f来说确是不可见的,因为f.__globals__实际等于foo.__dict__(简单而言就是命名空间不同)

fromfooimportf
print(f.__globals__)

假设我们在foo.py所有函数的外部预先定义了全局变量a,那么在将函数f导入时,a会随着f.__globals__一同被导入。但这时被导入的f.__globals__["a"]( 即foo.__dict__["a"]) 和bar.main中赋值的bar.main.__globals__["a"]( 即bar.__dict__["a"]) 仍然不是同一个变量,即赋值无法改变函数f的输出,如下面的例子所示。

#foo.py
a=3

deff():
print(a)

defmain():
globala
a=5
f()

if__name__=='__main__':
main()
#bar.py
fromfooimportf

defmain():
globala
a=4
f()

main()

运行bar.py输出3,而不是 4。

修改函数全局变量的值:更新globals

就上述例子而言,如果我们想在bar.py中改变函数f的输出,则需要直接更新其__globals__变量的值。

#bar.py
fromfooimportf

defmain():
f.__globals__['a']=4
f()

main()
  • 模块的dict变量和猴子布丁 (monkey-patching)

如上所述,函数的__globals__变量实际是其所属模块__dict__变量的引用。所以为了达到上面修改全局变量的目的,也可以直接更新foo.__dict__。修改模块foo的属性 (attribute) 值即可直接更新foo.__dict__。

#bar.py
importfoo
fromfooimportf


defmain():
foo.a=4
f()

如果你曾经使用过运行中给代码打补丁的库,一般就是这么实现的。直接修改被打补丁的模块的__dict__中特定的对象或函数。、

输入使得函数变得更加容易测试上面的例子中的函数f如果接受输入变量的话,而不是使用全局变量,代码将更容易被测试。同时可读性也更好,出了问题也更容易 debug。

#foo.py
deff(a):
print(a)


defmain():
a=5
f(a)

if__name__=='__main__':
main()
#bar.py
fromfooimportf

defmain():
a=3
f(a)

上述就是小编为大家分享的global关键字怎么在python中使用了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注恰卡编程网行业资讯频道。

发布于 2021-02-24 07:34:34
收藏
分享
海报
0 条评论
161
上一篇:如何在python sort函数中使用lambda表达式 下一篇:怎么在Vue中修改差值表达式
目录

    推荐阅读

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码