如何仅在对象上下文中执行python“评估”? [英] How do you do a python 'eval' only within an object context?

查看:90
本文介绍了如何仅在对象上下文中执行python“评估”?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以做类似的事情

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

在Python..ie中是否在对象 c的范围内对func1()和func2()进行了评估(如果它们是该类定义中的成员函数)?我无法进行简单的解析,因为对于我的应用程序,评估字符串可能会变得非常复杂。我猜想用ast模块做一些魔术也许可以解决问题,但是由于有关ast的文献很脏,所以我不确定在哪里看:

  import ast 

class MyTransformer(ast.NodeTransformer):
def visit_Name(self,node):
#做一个generic_visit,以便子节点是已处理的
ast.NodeVisitor.generic_visit(self,node)
返回ast.copy_location(
#对函数名称进行魔术操作,使它们成为
#方法调用一个公式对象
newnode,
节点


class公式(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表示arg中的args]))

def main():

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

#我们想模拟类似Formula()。eval(evalString)
node = ast.parse(evalString,mode ='eval')
MyTransformer()。visit(node)

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


解决方案

您几乎可以肯定不想这样做,但是您可以可以。 / p>

<$ c的上下文$ c> eval 是您要在其中评估代码的全局和局部字典。最常见的情况可能是 eval(expr,globals(), mycontext) eval(expr,mycontext),它们分别替换了默认的本地和全局上下文,而没有另一个。用对象的字典替换本地上下文类似于在该对象的内部(一种方法)运行—尽管请记住,成为成员函数的效果不如您期望的那样好拥有自己来调用其他成员函数…



无论如何,这是一个简单的示例:

 >> class Foo(object):
... def __init __(self):
... self.bar = 3
>> foo = Foo()
>> eval('bar',globals(),foo .__ dict__)
3

请注意, __ dict __ 可能并不是您想要的。例如:

 >> class Foo(object):
... @staticmethod
... def bar():
... return 3
>> foo = Foo()
>> eval(’bar()’,globals(),foo .__ dict__)
NameError:未定义名称 bar
>>> eval('bar()',globals(),{k:getattr(foo,k)for dir(foo)中的k}
3

要以所需方式进行此工作,您必须确切地知道如何用Python术语定义所需的内容-这需要了解一些有关对象在幕后的工作方式( MRO,也许是描述符等)。



如果您确实需要 eval ,并且您确实需要提供任意上下文,最好是显式地构建这些上下文(作为字典),而不是试图强制对象担任该角色:

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

此用法与您尝试在Python中模拟的Javascript风格更加接近



当然,与JS不同,Python不允许您在表达式中放入多行定义,因此对于复杂的情况,您必须执行以下操作:

 >> d ef bar():
...返回3
>>> foo = {
...’bar’:bar
...}
>>> eval('bar()',globals(),foo)

但是可以说,这几乎总是更易读(这基本上是Python背后不允许在表达式中使用多行定义的原因)。


Is it possible to do something like

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

in Python..i.e. have func1() and func2() be evaluated within the scope of the object 'c' (if they were member functions within that class definition)? I can't do a simple parsing, since for my application the eval strings can become arbitrarily complicated. I guess doing some magic with the ast module might do the trick, but due to the dirth of literature on ast, I'm not sure where to look:

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'))    

解决方案

You almost certainly don't want to do this, but you can.

The context for eval is the globals and locals dictionaries that you want to evaluate your code in. The most common cases are probably eval(expr, globals(), mycontext) and eval(expr, mycontext), which replace the default local and global contexts, respectively, leaving the other alone. Replacing the local context with an object's dictionary is similar to running "within" (a method of) that object—although keep in mind that "being a member function" doesn't do as much good as you might expect if you don't have a self to call other member functions on…

Anyway, here's a quick example:

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

Keep in mind that __dict__ may not be exactly what you want here. For example:

>>> 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

To make this work the way you want, you have to know exactly how to define you want, in Python terms—which requires knowing a bit about how objects works under the covers (MRO, maybe descriptors, etc.).

If you really need eval, and you really need to provide arbitrary contexts, you're probably better building those contexts explicitly (as dictionaries) rather than trying to force objects into that role:

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

This use is much closer to the Javascript style you're trying to emulate in Python anyway.

Of course, unlike JS, Python doesn't let you put multi-line definitions inside an expression, so for complex cases you have to do this:

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

But arguably that's almost always more readable (which is basically the argument behind Python not allowing multi-line definitions in expressions).

这篇关于如何仅在对象上下文中执行python“评估”?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆