【问题标题】:Insert variable into global namespace from within a function? [duplicate]从函数内将变量插入全局命名空间? [复制]
【发布时间】:2012-08-02 12:56:12
【问题描述】:

是否可以编写一个将对象插入全局命名空间并将其绑定到变量的函数?例如:

>>> 'var' in dir()
False
>>> def insert_into_global_namespace():
...        var = "an object"
...        inject var
>>> insert_into_global_namespace()
>>> var
"an object"

【问题讨论】:

    标签: python namespaces


    【解决方案1】:

    Roland Puntaier's answer 的更简洁版本是:

    import builtins
    
    def insert_into_global_namespace():
        builtins.var = 'an object'
    

    【讨论】:

    • 在我尝试过的几十个“解决方案”中,这是唯一一个真正有效且简洁的解决方案!
    【解决方案2】:

    就这么简单

    globals()['var'] = "an object"
    

    和/或

    def insert_into_namespace(name, value, name_space=globals()):
        name_space[name] = value
    
    insert_into_namespace("var", "an object")
    

    注意globals 是一个内置关键字,即'globals' in __builtins__.__dict__ 的计算结果为True

    【讨论】:

    • 这是迄今为止最好的答案。没有理由像其他答案建议的那样做任何奇怪的魔法。我很遗憾我没有早点看到这个答案。
    • IMO 给函数的 name_space 参数一个默认值 None 会更好,然后在函数内部,使用调用函数的全局变量作为默认命名空间。否则给出。即if name_space is None: name_space = sys._getframe(1).f_globals。这样做可以让其他脚本更容易地使用这个函数,因为它当前的编码方式,默认命名空间是 insert_into_namespace() 函数本身在其中定义的任何脚本/模块的命名空间 - 所以只能被其他函数访问同样的脚本。
    • 能否举个代码示例,上面的参数name_space的默认值和当前作用域globals()的值不同?
    【解决方案3】:
    var = ""
    
    def insert_global():    
        global var
        var = "saher"
    
    insert_global()
    print var
    

    【讨论】:

      【解决方案4】:

      我认为没有人解释过如何创建和设置名称本身就是变量值的全局变量。

      这是一个我不喜欢的答案,但至少它有效[1],通常是[2]。

      我希望有人能告诉我一个更好的方法。我发现了几个用例,实际上我正在使用这个丑陋的答案:

      ########################################
      def insert_into_global_namespace(
          new_global_name,
          new_global_value = None,
      ):
          executable_string = """
      global %s
      %s = %r
      """ % (
              new_global_name,
              new_global_name, new_global_value,
          )
          exec executable_string  ## suboptimal!
      
      if __name__ == '__main__':
          ## create global variable foo with value 'bar':
          insert_into_global_namespace(
              'foo',
              'bar',
          )
          print globals()[ 'foo']
      ########################################
      
      1. 出于多种原因,应避免使用 Python exec。

      2. 注意:请注意“exec”行中缺少“in”关键字(“unqualified exec”)。

      【讨论】:

      • 你可以做globals()[new_global_name] = new_global_value
      【解决方案5】:

      但请注意,分配声明为全局的函数变量只会注入模块命名空间。导入后不能全局使用这些变量:

      from that_module import call_that_function
      call_that_function()
      print(use_var_declared_global)
      

      你得到

      NameError: global name 'use_var_declared_global' is not defined
      

      您必须再次导入才能导入那些新的“模块全局变量”。 内置模块是“真正的全局”:

      class global_injector:
          '''Inject into the *real global namespace*, i.e. "builtins" namespace or "__builtin__" for python2.
          Assigning to variables declared global in a function, injects them only into the module's global namespace.
          >>> Global= sys.modules['__builtin__'].__dict__
          >>> #would need 
          >>> Global['aname'] = 'avalue'
          >>> #With
          >>> Global = global_injector()
          >>> #one can do
          >>> Global.bname = 'bvalue'
          >>> #reading from it is simply
          >>> bname
          bvalue
      
          '''
          def __init__(self):
              try:
                  self.__dict__['builtin'] = sys.modules['__builtin__'].__dict__
              except KeyError:
                  self.__dict__['builtin'] = sys.modules['builtins'].__dict__
          def __setattr__(self,name,value):
              self.builtin[name] = value
      Global = global_injector()
      

      【讨论】:

        【解决方案6】:

        是的,只需使用global 语句。

        def func():
            global var
            var = "stuff"
        

        【讨论】:

        • 如果直到运行时才知道变量的名称怎么办?
        • @martineau:首先,这不是最初的问题。无论如何,一般来说,如果你试图分配一个直到运行时你才知道名称的变量,你可能做错了什么。如果您不知道它的名称,您以后将如何使用该变量?通常,如果您要创建具有特定名称的变量,最好制作一个字典并使用“名称”作为键。
        • 是的,我知道这不是最初的问题。至于一个实际的用例,考虑一个调用者通过参数告诉函数要创建什么名称,然后在同一个模块中使用它们以及假设它们已定义的其他代码。有点像from xxx import yyy 语句,除了yyy 是一个字符串。
        • @martineau: globals()['varname'] = 'varvalue'
        • @gsk:这种众所周知的技术只将名称插入到函数所在模块的命名空间中,这可能与调用者的命名空间不同。
        猜你喜欢
        • 2012-03-13
        • 2012-12-28
        • 2011-03-25
        • 2014-12-30
        • 2013-08-12
        • 2011-08-31
        • 2017-01-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多