3

我有一个脚本如下

from mapper import Mapper

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

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

Mapper在文件中定义mapper.py

Mapper = {'test': a.foo}

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

NameError: name 'a' is not defined

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

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

附加信息:

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

2 回答 2

1

除非有安全漏洞eval,否则不能在其中使用名称amapper.py除非该名称在某处定义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“注册”该对象。这使您只需传递对象一次即可注册它,然后您不必每次调用都传递它:aMappera

# 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而不是常规 dict 来简化这一点,并让该类在其中做一些工作__getitem__以查看“已知位置”(例如,读取一些模块变量)以用作评估的基础a。不过,这将是一个更重的解决方案。

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

于 2013-02-12T19:36:41.633 回答
0

我不确定我是否完全遵循,但可以从任何引用 Mapper 的地方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']()
于 2013-02-12T18:10:07.537 回答