【问题标题】:How to resolve a global variable in a module?如何解析模块中的全局变量?
【发布时间】:2013-01-28 03:14:45
【问题描述】:

我有一个脚本如下

from mapper import Mapper

class A(object):
    def foo(self):
        print "world"

a = A()
a.foo()
Mapper['test']()

在文件mapper.py中定义Mapper:

Mapper = {'test': a.foo}

我想定义一个函数调用来引用一个未在mapper.py 中定义但在原始代码中定义的对象。但是上面的代码给出了错误

NameError: name 'a' is not defined

这是有道理的,因为a 本身没有在mapper.py 中定义。但是,是否可以更改代码以让代码在主代码本身中进行名称解析,或者通过使用globals 或其他方式?

为了解决这个问题,我可以将mapper.py 中的实现指定为文本并在主代码中使用eval,但我想避免使用eval。

补充资料:

  • 函数的完整定义必须在mapper.py
  • 事先不知道实例a 是什么,或者它是从什么类实例化的。

【问题讨论】:

    标签: python module python-2.7 global-variables


    【解决方案1】:

    我不确定我是否完全遵循,但a 可以从任何引用 Mapper 的地方“注册”Mapper 的方法:

    #mapping.py
    Mapper = {}
    

    然后:

    #main.py
    from mapping import Mapper
    
    #snip
    a = A()
    Mapper['test'] = a.foo #put your instance method into the Mapper dict.
    #snip
    
    Mapper['test']()
    

    【讨论】:

    • 不,抱歉,这不是我想要的。对于任何实例a,函数的完整定义必须在mapper.py 中给出。事先不知道a 是什么。我会在问题中澄清。
    • @Alex:如果您不知道对象是什么,就不能指望“完整定义”。在某些时候,您必须指定该对象是什么。
    【解决方案2】:

    除非像eval 这样的安全漏洞,否则不能在mapper.py 中使用名称a,除非该名称在mapper.py 中的某处定义或从另一个模块导入。没有办法让mapper.py 自动且静默地访问来自不同模块的值a。

    此外,如果您只是在示例中的字典中使用它,则 a.foo 将在创建字典后立即进行评估。它不会等到您真正调用该函数;一旦它评估a.foo 来创建字典,它就会失败,因为它不知道a 是什么。

    您可以通过将元素包装在函数中来解决第二个问题(为简洁起见,使用 lambda):

    Mapper = {'test': lambda: a.foo}
    

    。 . .但这仍然无济于事,除非你能以某种方式让a 在mapper.py 中可用。

    一种可能性是通过“神秘”对象参数化您的Mapper,然后将该对象从外部传入:

    # mapper.py
    Mapper = {'test': lambda a: a.foo}
    
    # other module
    from mapper import Mapper
    Mapper['test'](a)()
    

    或者,类似于mgilson 的建议,您可以通过Mapper 以某种方式“注册”对象a。这让您只需传递对象a 一次即可注册它,然后您不必每次调用都传递它:

    # mapper.py
    Mapper = {'test': lambda a: Mapper['a'].foo}
    
    # other module
    from mapper import Mapper
    Mapper['a'] = a
    Mapper['test']()()
    

    请注意末尾的两组括号:一组用于评估 lambda 并提取您要调用的函数,第二组用于实际调用该函数。你可以做一个类似的处理,而不是使用Mapper['a']作为参考,使用模块级变量:

    # mapper.py
    Mapper = {'test': lambda: a.foo}
    
    # other module
    import mapper
    Mapper = mapper.Mapper
    
    mapper.a = a
    Mapper['test']()()
    

    请注意,这需要您执行import mapper 才能在其他模块中设置模块变量。

    您可以通过为Mapper 使用自定义类而不是常规字典来简化这一点,并让该类在其__getitem__ 中执行一些工作以查看“已知位置”(例如,读取一些模块变量) 用作评估a 的基础。不过,这将是一个更重的解决方案。

    最重要的是,您根本不能(同样,不使用eval 或其他此类漏洞)在mapper.py 中编写使用未定义变量a 的代码,然后在其中定义变量a另一个模块并让mapper.py 自动知道这一点。某处必须有一些代码行“告诉”mapper.py 您希望它使用 a 的什么值。

    【讨论】:

      猜你喜欢
      • 2022-09-28
      • 2016-02-10
      • 2015-02-27
      • 1970-01-01
      • 2015-03-07
      • 1970-01-01
      • 1970-01-01
      • 2016-10-20
      • 2016-09-15
      相关资源
      最近更新 更多