代码之家  ›  专栏  ›  技术社区  ›  Waman

globals()['variable']=在.py文件中设置的值在用于其他.py文件时不反映值更改

  •  0
  • Waman  · 技术社区  · 7 年前

    GualAlx1.Py :

    globals()['a']='100'
    
    def setvalue(val):
        globals()['a'] = val
    

    GualAlx2.Py :

    from globalEx1 import *
    
    print a
    setvalue('200')
    print a 
    

    论执行 globalEx2.py :

    输出:

    100
    100
    

    我怎样才能改变 globals['a'] 使用函数,以便它在.py文件中反映?

    3 回复  |  直到 7 年前
        1
  •  4
  •   gilch    7 年前

    每个模块都有自己的全局。python的行为与预期完全一致。更新 globalEx1 a 指出别的事情不会影响 globalEx2 是指。

    围绕这一点,有各种各样的方法,具体取决于你想要什么。

    1. 再进口 setvalue() 呼叫
    2. return a 然后分配它,就像 a = setvalue() .
    3. import globalEx1 使用 globalEx1.a 而不是 . (或使用) import globalEx1 as 还有一个较短的名字。)
    4. 通过 GualAlx2 globals() 作为一个论点 setvalue 并在上面设置值。
    5. 制作 可变对象 包含 你的价值,比如列表、口述或 types.SimpleNamespace 然后变异 设定值 .
    6. 使用 inspect 里面 设定值 从堆栈帧中获取调用方的全局数据。(方便,但易碎。)

    最后一个选项看起来适合我……它可以在代码更改最小的情况下完成工作,但是我可以用相同的方式更新多个模块的全局吗?或者它只给我打电话的人的全局信息?

    选项6实际上是最危险的。调用者本身基本上成为函数的一个隐藏参数,因此类似于来自另一个模块的装饰器的东西可以在不发出警告的情况下破坏它。选项4只是使隐藏的参数显式化,所以它不那么脆弱。

    如果您需要在两个以上的模块之间工作,那么选项6就不够好,因为它只提供当前的调用堆栈。选项3可能是最可靠的,因为你似乎正在尝试做什么。


    选项1如何工作?我的意思是重新运行->“from globalx1 import*”,因为我有很多变量,比如“a”。

    模块在第一次导入时成为对象,并保存在 sys.modules 缓存,因此再次导入不会再次执行模块。一 from ... import (甚至与 * )只需从该模块对象获取属性,并将它们添加到本地作用域(如果在顶级完成,则为模块全局,即在任何定义之外)。

    模块对象的 __dict__ 基本上是它的全局,所以任何改变模块全局的函数都会影响生成的模块对象的属性,即使它是在模块导入之后完成的。

    我们不能从python函数的“globalx1 import*”中执行此操作,还有其他选择吗?

    星形语法只允许在顶层使用。但请记住,它只是从模块对象中读取属性。这样您就可以获得所有模块属性的dict,比如

    return vars(globalEx1)
    

    这会给你更多 * 会。它不返回以 _ 默认情况下,或 __all__ 否则。你可以用听写理解来过滤结果听写,甚至 .update() 其他模块的全局指令和结果。

    但是,您可以使用exec使其成为顶级,而不是重新实现这个过滤逻辑。那么你能拿到的唯一奇怪的钥匙是 __builtins__

    namespace = {}
    exec('from globalEx1 import *', namespace)
    del namespace['__builtins__']
    return namespace
    

    然后你可以 globals().update(namespace) 或者什么。

    使用 exec 像这样可能被认为是不好的形式,但那也是 import * 首先,老实说。

        2
  •  1
  •   gilch    7 年前

    这是一个有趣的问题,与字符串是不可变的这一事实有关。线 from globalEx1 import * 在中创建两个引用 globalEx2 模块: a setvalue . globalEx2.a 最初引用的字符串对象与 globalEx1.a 因为进口就是这样运作的。

    但是,一旦你打电话 设定值 在全球范围内 globalEx1 ,引用的值 GualAlx1.a 被另一个字符串对象替换。由于字符串是不可变的,因此无法在适当的位置执行此操作。价值 GualAlx2.a 仍然绑定到原始字符串对象,正如它应该的那样。

    这里有几个解决办法。最要紧的是把进口的东西 GualAlx2 :

    import globalEx1
    
    print globalEx1.a
    globalEx1.setvalue('200')
    print globalEx1.a
    

    另一种选择是使用可变容器 以及访问:

    globals()['a']=['100']
    
    def setvalue(val):
        globals()['a'][0] = val
    
    from globalEx1 import *
    
    print a[0]
    setvalue('200')
    print a[0]
    

    第三种选择是 GualAlx2 设定值 原始函数的副本,但 __globals__ 属性设置为的命名空间 GualAlx2 而不是 GraceLex1 :

    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
    ...
    

    你要复印的原因是 γ粒子 是只读属性,而且您也不想在 GraceLex1 . 见 https://stackoverflow.com/a/13503277/2988730 .

        3
  •  0
  •   Tim    7 年前

    全局在import语句的开头只导入一次。因此,如果全局是不可变的对象(如str、int等),则不会反映任何更新。但是,如果全局是一个可变的对象,比如列表等,那么更新将被反映出来。例如,

    GualAlx1.Py:

    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