简体   繁体   English

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

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

I have a script as follows 我有一个脚本如下

from mapper import Mapper

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

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

with Mapper defined in the file mapper.py : 使用mapper.py文件中定义的Mapper

Mapper = {'test': a.foo}

where I want to define a function call referencing an object not defined in mapper.py , but in the original code. 我想在哪里定义一个函数调用,引用一个未在mapper.py定义的对象,但在原始代码中。 However the code above gives the error 但是上面的代码给出了错误

NameError: name 'a' is not defined

which makes kind of sense, as a is not defined in mapper.py itself. 这使得那种感觉,作为a没有定义mapper.py本身。 However, is it possible to change the code to let the code do the name resolution in the main code itself, or by the use of globals or something? 但是,是否可以更改代码以使代码在主代码本身中执行名称解析,或者使用globals或其他东西?

To solve this problem I could specify the implementation in mapper.py as a text and use eval in the main code, but I would like to avoid the usage of eval . 为了解决这个问题,我可以将mapper.py的实现指定为文本,并在主代码中使用eval ,但我想避免使用eval

Additional information: 附加信息:

  • The full definition of the function has to be made in mapper.py 函数的完整定义必须在mapper.py
  • It is not known beforehand what the instance a is, or from what clas it is instantiated. 这是事先不知道的情况是什么a是,或什么CLAS它被实例化。

Barring security holes like eval , it's not possible to use a name a in mapper.py unless the name is either defined somewhere in mapper.py or imported from another module. 除非像eval这样的安全漏洞,否则无法在mapper.py使用名称a ,除非该名称在mapper.py某处定义或从其他模块导入。 There is no way to just let mapper.py automatically and silently access a value a from a different module. 没有办法让mapper.py自动并静默地访问来自不同模块的值a

In addition, if you're using it just in a dict as in your example, a.foo is going to be evaluated as soon as the dict is created. 另外,如果你只是在你的例子中的dict中使用它, a.foo将在创建dict时立即进行评估。 It's not going wait until you actually call the function; 它不会等到你实际调用该函数; as soon as it evaluates a.foo to create the dict, it will fail because it doesn't know what a is. 只要它计算a.foo创建字典,它会失败,因为它不知道是什么a是。

You could get around this second problem by wrapping the element in a function (using a lambda for brevity): 您可以通过将元素包装在函数中来解决第二个问题(为简洁起见使用lambda):

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

. . . but this still won't help unless you can somehow get a to be available inside mapper.py . 但这仍然不会帮助,除非你能以某种方式得到a可用的内部mapper.py

One possibility is to parameterize your Mapper by the "mystery" object and then pass that object in from outside: 一种可能性是通过“神秘”对象对Mapper进行参数化,然后从外部传递该对象:

# mapper.py
Mapper = {'test': lambda a: a.foo}

# other module
from mapper import Mapper
Mapper['test'](a)()

Or, similar to what mgilson suggested, you could "register" the object a with Mapper somehow. 或者,类似于mgilson建议的,你可以用Mapper以某种方式“注册”对象a This lets you pass the object a only once to register it, and then you don't have to pass it for every call: 这使您可以传递对象a唯一的一次注册,然后你不必把它传递每一个呼叫:

# mapper.py
Mapper = {'test': lambda a: Mapper['a'].foo}

# other module
from mapper import Mapper
Mapper['a'] = a
Mapper['test']()()

Note the two sets of parentheses at the end there: one set to evaluate the lambda and extract the function you want to call, and the second set to actually call that function. 注意那里的两组括号:一组用于评估lambda并提取你想要调用的函数,另一组用于实际调用该函数。 You could do a similar deal by, instead of using Mapper['a'] as the reference, using a module-level variable: 您可以使用模块级变量执行类似的处理,而不是使用Mapper['a']作为引用:

# mapper.py
Mapper = {'test': lambda: a.foo}

# other module
import mapper
Mapper = mapper.Mapper

mapper.a = a
Mapper['test']()()

Note that this requires you to do import mapper in order to set the module variable in that other module. 请注意,这需要您执行import mapper以便在该其他模块中设置模块变量。

You could streamline this somewhat by using a custom class for Mapper instead of a regular dict, and having that class do some work in its __getitem__ to look in a "known location" (eg, read some module variable) to use as a base for evaluating a . 您可以通过使用Mapper的自定义类而不是常规字典来简化这一点,并让该类在其__getitem__执行一些工作以查看“已知位置”(例如,读取某个模块变量)以用作基础评估a That would be a heavier-weight solution though. 不过,这将是一个更重的解决方案。

The bottom line is that you simply cannot (again, without the use of eval or other such holes) write code in mapper.py that uses an undefined variable a , and then define a variable a in another module and have mapper.py automatically know about that. 底线是你根本不能(再次,没有使用eval或其他这样的漏洞)在mapper.py中编写使用未定义变量a ,然后在另一个模块中定义变量a并让mapper.py自动知道关于那个。 There has to be some line of code somewhere that "tells" mapper.py what value of a you want it to use. 必须有一些代码行,某处“讲述” mapper.py什么价值a你想使用它。

I'm not sure I completely follow, but a could "register" it's method with Mapper from anywhere which has a reference to Mapper: 我不知道我完全跟随,而是a可以“注册”这是法Mapper由具有参考映射器的任何地方:

#mapping.py
Mapper = {}

and then: 接着:

#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