你怎么只在对象上下文做一个python“EVAL”?(How do you do a python

2019-08-04 05:13发布

是否有可能做这样的事情

c = MyObj()
c.eval("func1(42)+func2(24)")

在Python..ie具有func1的()和FUNC2()对象“C”的范围之内进行评估(如果他们是该类定义中的成员函数)? 我不能做一个简单的分析,因为我的应用程序中的eval字符串可以成为任意复杂。 我猜做一些魔法与AST模块可能做的伎俩,但由于对AST文学dirth,我不知道去哪里找:

import ast

class MyTransformer(ast.NodeTransformer):
    def visit_Name(self, node):
        # do a generic_visit so that child nodes are processed
        ast.NodeVisitor.generic_visit(self, node)
        return ast.copy_location(
            # do something magical with names that are functions, so that they become 
            # method calls to a Formula object
            newnode,
            node
        )

class Formula(object):

    def LEFT(self, s, n):
        return s[:n]

    def RIGHT(self, s, n):
        return s[0-n:]

    def CONCAT(self, *args, **kwargs):
        return ''.join([arg for arg in args])

def main():

    evalString = "CONCAT(LEFT('Hello', 2), RIGHT('World', 3))"

    # we want to emulate something like Formula().eval(evalString)
    node = ast.parse(evalString, mode='eval')
    MyTransformer().visit(node)

    ast.fix_missing_locations(node)
    print eval(compile(node, '<string>', mode='eval'))    

Answer 1:

你几乎肯定不希望这样做,但你可以

对于上下文eval是要评估在你的代码中的全局和当地人词典,最常见的情况是可能eval(expr, globals(), mycontext)eval(expr, mycontext)取代默认的本地和全球上下文,分别留下其他孤单。 与对象的字典更换当地的情况是类似“内”运行(的方法)对象 - 虽然牢记,“作为一个成员函数”并不做尽可能多好,如果你没有,你可能期望有一个self来调用其他成员函数...

总之,这里是一个简单的例子:

>>> class Foo(object):
...     def __init__(self):
...         self.bar = 3
>>> foo = Foo()
>>> eval('a', globals(), foo.__dict__)
3

请记住, __dict__可能不是你想在这里什么。 例如:

>>> class Foo(object):
...     @staticmethod
...     def bar():
...         return 3
>>> foo = Foo()
>>> eval('bar()', globals(), foo.__dict__)
NameError: name 'bar' is not defined
>>> eval('bar()', globals(), {k: getattr(foo, k) for k in dir(foo)}
3

为了使这项工作您想要的方式,你必须知道如何定义你想要的,在Python方面,它需要知道一点关于如何盖(MRO,也许描述符等)下的对象的作品。

如果你真的需要eval ,你真的需要提供任意环境中,你可能会更好构建这些上下文明确(如字典),而不是试图迫使物体进入那个角色:

>>> foo = {
...     'bar': lambda: 3
... }
>>> eval('bar()', globals(), foo)

这种使用是更接近你想在Python效仿反正JavaScript的风格。

当然,不同的JS,Python没有让你把多行定义一个表达式中,因此对于复杂的情况下,你必须这样做:

>>> def bar():
...     return 3
>>> foo = {
...     'bar': bar
... }
>>> eval('bar()', globals(), foo)

不过,事实上这几乎总是更可读的(这基本上是落后的Python不允许在表达式多行定义的参数)。



Answer 2:

所以,我建议你做这样的事情:

>>> class S(object):
...     def add(self, a, b):
...         return a + b
... 
>>> filter(lambda (k,v): not k.startswith("__"), S.__dict__.items())
[('add', <function add at 0x109cec500>)]
>>> target = S()
>>> map(lambda (k, f): (k, f.__get__(target, S)), filter(lambda (k,v): not k.startswith("__"), S.__dict__.items()))
[('add', <bound method S.add of <__main__.S object at 0x109ce4ed0>>)]
>>> dict(_)
{'add': <bound method S.add of <__main__.S object at 0x109ce4ed0>>}
>>> eval("add(45, 10) + add(10, 1)", _, {})
66

好像你需要的。 让我来解释一下这是如何工作的。

  1. eval接受当地人和全局作为参数。
  2. 因此,我们需要定义特殊的全球背景下,这将是你的类的“代表”。
  3. 要做到这一点,我们需要提供作为globals的所有“有价值的” 有限方法字典。
  4. 从simples部分开始。 我们有S类定义。 如何让所有的“宝贵”的方法呢? 简单的filter ,从名字S.__dict__为了检查方法名称是否从开始__或没有(你看,作为结果,我们得到名单有1项- add功能)。
  5. 创建target的=实例S类,这将是“EVAL语境”。
  6. 下一步是最“靠谱”。 我们需要从每个函数创建“绑定的方法”。 要做到这一点,我们使用这些事实,该类__dict__商店功能,每个功能的非数据描述符和界方法可以简单地被撷取func.__get__(obj, type(obj)) 在执行此操作map
  7. 就拿上一步骤产生,创建dict从它。
  8. 通过为globalseval功能。

我希望这个能帮上忙。



Answer 3:

以上建议填充液locals适用于大多数情况下,但在性质(数据描述)的情况下,可能会有问题。 填充字典时,这些被评估一次 。 这意味着,相同的变量名多次引用总是会返回完全相同的情况下,这可能不是预期中的属性时的行为。

这个问题可以通过注意被解决eval期望一个locals的论点,即表现得像dict (相对于全局变量,它必须一个dict )。 换句话说,我们可以重写__getitem__在您的实例上的实例的上下文飞解决变量名称,并直接把它作为locals归因于eval 。 你的例子因此可以实现:

class Formula(object):
    def __getitem__(self, key):
        if key not in dir(self) or key.startswith('__'):
            raise KeyError(key)
        return getattr(self, key)

    def LEFT(self, s, n):
        return s[:n]

    def RIGHT(self, s, n):
        return s[0-n:]

    def CONCAT(self, *args, **kwargs):
        return ''.join([arg for arg in args])


def main():
    evalString = "CONCAT(LEFT('Hello', 2), RIGHT('World', 3))"
    print eval(evalString, {}, Formula())

if __name__ == "__main__":
    main()

这一招应该继承,静态方法,类方法和属性的作用。 最后,使用dirgetattr避免了需要直接与互动__dict____mro__ ,虽然结果dir可能并不总是完整 。



Answer 4:

你可能有一个看接受这个问题的答案: “获得是在与语句要执行的命令块” 。

这是一个有用的方式为我创造我自己的背景,其中在矩形阵列,如Python熊猫数据帧的数学运算,“只是工作”,而无需使用额外的丑熊猫语法来打扰。 例如,当我写“ a = x*y ”的上下文之内,它自动分配a作为对上下文对象中的属性,并且它知道与上下文对象的执行矢量操作xy属性。

,我发现这方面的东西是非常非常有帮助的,尽管事实上,每当我问StackOverflow上,我经常收到trollish响应,它不能是我真正想做的事情。

你也许可以得到这个在该环境中工作eval查找功能了。



文章来源: How do you do a python 'eval' only within an object context?