繁体   English   中英

如何解决模块中的全局变量?

[英]How to resolve a global variable in a module?

我有一个脚本如下

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是,或什么CLAS它被实例化。

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

另外,如果你只是在你的例子中的dict中使用它, a.foo将在创建dict时立即进行评估。 它不会等到你实际调用该函数; 只要它计算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你想使用它。

我不知道我完全跟随,而是a可以“注册”这是法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']()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM