2024-10-03 09:10:08 发布
网友
全局1.py:
globals()['a']='100' def setvalue(val): globals()['a'] = val
globalEx2.py:
from globalEx1 import * print a setvalue('200') print a
在执行globalEx2.py时:
globalEx2.py
输出:
100 100
如何使用函数更改globals['a']的值,使其反映在.py文件中?你知道吗
globals['a']
这是一个有趣的问题,因为字符串是不可变的。行from globalEx1 import *在globalEx2模块中创建了两个引用:a和setvalue。globalEx2.a最初是指与globalEx1.a相同的字符串对象,因为导入就是这样工作的。你知道吗
from globalEx1 import *
globalEx2
a
setvalue
globalEx2.a
globalEx1.a
但是,一旦调用setvalue,它对globalEx1的全局变量进行操作,globalEx1.a引用的值就会被另一个string对象替换。由于字符串是不可变的,因此无法在适当的位置执行此操作。globalEx2.a的值仍然绑定到原始string对象,正如它应该绑定的那样。你知道吗
globalEx1
你这里有一些解决办法。最具python风格的是在globalEx2中修复导入:
import globalEx1 print globalEx1.a globalEx1.setvalue('200') print globalEx1.a
另一种选择是为a使用可变容器,并访问:
globals()['a']=['100'] def setvalue(val): globals()['a'][0] = val
from globalEx1 import * print a[0] setvalue('200') print a[0]
第三个也是更为广泛的选择是使globalEx2的setvalue成为原始函数的副本,但将其__globals__属性设置为globalEx2的命名空间,而不是globalEx1:
__globals__
from functools import update_wrapper from types import FunctionType from globalEx1 import * _setvalue = FunctionType(setvalue.__code__, globals(), name=setvalue.__name__, argdefs=setvalue.__defaults__, closure=setvalue.__closure__) _setvalue = functools.update_wrapper(_setvalue, setvalue) _setvalue.__kwdefaults__ = f.__kwdefaults__ setvalue = _setvalue del _setvalue print a ...
必须创建副本的原因是__globals__是只读属性,而且您不想弄乱globalEx1中的函数。见https://stackoverflow.com/a/13503277/2988730。你知道吗
全局变量仅在import语句开头导入一次。因此,如果global是一个不可变的对象,比如str、int等,则不会反映任何更新。但是,如果global是一个可变的对象,比如list等,则会反映更新。例如
globals()['a']=[100] def setvalue(val): globals()['a'][0] = val
输出将按预期更改:
[100] [200]
像普通变量一样定义全局变量更容易:
a = [100] def setvalue(value): a[0] = value
或在编辑不可变对象的值时:
a = 100 def setvalue(value): global a a = value
每个模块都有自己的全局变量。Python的行为完全符合预期。更新globalEx1的a指向其他对象不会影响globalEx2的a指向的位置。你知道吗
有各种各样的方法来解决这个问题,具体取决于你想要什么。你知道吗
setvalue()
return a
a = setvalue()
import globalEx1
import globalEx1 as
globals()
types.SimpleNamespace
inspect
Last option looks suitable for me.. it will do the job with minimal code change but can I update globals of multiple modules using same way? or it only gives me the caller's globals?
选项6实际上是最危险的。调用者本身基本上成为函数的一个隐藏参数,因此来自另一个模块的装饰器之类的东西可以在没有警告的情况下破坏它。选项4只是将隐藏参数显式化,所以它不那么脆弱。你知道吗
如果您需要在两个以上的模块上使用它,那么选项6就不够好,因为它只提供当前的调用堆栈。选项3可能是最可靠的你似乎要做的事。你知道吗
How does option 1 work? I mean is it about running again -> "from globalEx1 import *" because I have many variables like 'a'.
模块在第一次导入时成为对象,并且保存在sys.modules缓存中,因此再次导入不会再次执行模块。from ... import(即使使用了*)也只是从模块对象获取属性,并将它们添加到本地范围(如果在顶层完成,那么就是模块全局变量,也就是在任何定义之外)
sys.modules
from ... import
*
模块对象的__dict__基本上是它的全局变量,因此任何改变模块全局变量的函数都会影响结果模块对象的属性,即使它是在导入模块之后完成的。你知道吗
__dict__
We cannot do from 'globalEx1 import *' from a python function, any alternative to this?
star语法只允许在顶层使用。但请记住,它只是从模块对象读取属性。所以你可以得到所有模块属性的dict,比如
return vars(globalEx1)
这会给你比*更多的东西。默认情况下,它不返回以_开头的名称,否则不返回在__all__中指定的子集。您可以使用dict comprehension过滤结果dict,甚至.update()使用结果过滤其他模块的全局dict。你知道吗
_
__all__
.update()
但是,与其重新实现这个过滤逻辑,不如使用exec使其成为顶层。那么你得到的唯一奇怪的钥匙就是__builtins__
__builtins__
namespace = {} exec('from globalEx1 import *', namespace) del namespace['__builtins__'] return namespace
然后你就可以globals().update(namespace)或者别的什么了。你知道吗
globals().update(namespace)
像这样使用exec可能被认为是不好的形式,但老实说,import *也是如此。你知道吗
exec
import *
这是一个有趣的问题,因为字符串是不可变的。行
from globalEx1 import *
在globalEx2
模块中创建了两个引用:a
和setvalue
。globalEx2.a
最初是指与globalEx1.a
相同的字符串对象,因为导入就是这样工作的。你知道吗但是,一旦调用
setvalue
,它对globalEx1
的全局变量进行操作,globalEx1.a
引用的值就会被另一个string对象替换。由于字符串是不可变的,因此无法在适当的位置执行此操作。globalEx2.a
的值仍然绑定到原始string对象,正如它应该绑定的那样。你知道吗你这里有一些解决办法。最具python风格的是在
globalEx2
中修复导入:另一种选择是为
a
使用可变容器,并访问:第三个也是更为广泛的选择是使
globalEx2
的setvalue
成为原始函数的副本,但将其__globals__
属性设置为globalEx2
的命名空间,而不是globalEx1
:必须创建副本的原因是
__globals__
是只读属性,而且您不想弄乱globalEx1
中的函数。见https://stackoverflow.com/a/13503277/2988730。你知道吗全局变量仅在import语句开头导入一次。因此,如果global是一个不可变的对象,比如str、int等,则不会反映任何更新。但是,如果global是一个可变的对象,比如list等,则会反映更新。例如
全局1.py:
输出将按预期更改:
旁白
像普通变量一样定义全局变量更容易:
或在编辑不可变对象的值时:
每个模块都有自己的全局变量。Python的行为完全符合预期。更新
globalEx1
的a
指向其他对象不会影响globalEx2
的a
指向的位置。你知道吗有各种各样的方法来解决这个问题,具体取决于你想要什么。你知道吗
setvalue()
调用之后重新导入a
return a
并赋值,如a = setvalue()
。你知道吗import globalEx1
并使用globalEx1.a
而不是a
。(或使用import globalEx1 as
和较短的名称。)globalEx2
的globals()
作为参数传递给setvalue
,并设置该参数的值。你知道吗a
成为一个包含您的值的可变对象,如list、dict或types.SimpleNamespace
,并在setvalue
中对其进行变异。你知道吗setvalue
内使用inspect
从调用方的堆栈帧获取调用方的全局变量。(方便,但易碎。)选项6实际上是最危险的。调用者本身基本上成为函数的一个隐藏参数,因此来自另一个模块的装饰器之类的东西可以在没有警告的情况下破坏它。选项4只是将隐藏参数显式化,所以它不那么脆弱。你知道吗
如果您需要在两个以上的模块上使用它,那么选项6就不够好,因为它只提供当前的调用堆栈。选项3可能是最可靠的你似乎要做的事。你知道吗
模块在第一次导入时成为对象,并且保存在
sys.modules
缓存中,因此再次导入不会再次执行模块。from ... import
(即使使用了*
)也只是从模块对象获取属性,并将它们添加到本地范围(如果在顶层完成,那么就是模块全局变量,也就是在任何定义之外)模块对象的
__dict__
基本上是它的全局变量,因此任何改变模块全局变量的函数都会影响结果模块对象的属性,即使它是在导入模块之后完成的。你知道吗star语法只允许在顶层使用。但请记住,它只是从模块对象读取属性。所以你可以得到所有模块属性的dict,比如
这会给你比
*
更多的东西。默认情况下,它不返回以_
开头的名称,否则不返回在__all__
中指定的子集。您可以使用dict comprehension过滤结果dict,甚至.update()
使用结果过滤其他模块的全局dict。你知道吗但是,与其重新实现这个过滤逻辑,不如使用exec使其成为顶层。那么你得到的唯一奇怪的钥匙就是
__builtins__
然后你就可以
globals().update(namespace)
或者别的什么了。你知道吗像这样使用
exec
可能被认为是不好的形式,但老实说,import *
也是如此。你知道吗相关问题 更多 >
编程相关推荐