什么是Python AST中的Expr? [英] What is an Expr in Python AST?
问题描述
我正在使用Python动态生成代码。
I'm working on dynamically generating code in Python.
为此,我编写了一个辅助方法,该方法接收一串Python代码并转储出去。 AST。这就是这种方法:
To aid with this, I wrote a helper method which takes in a string of Python code and dumps out the AST. Here's that method:
# I want print treated as a function, not a statement.
import __future__
pfcf = __future__.print_function.compiler_flag
from ast import dump, PyCF_ONLY_AST
def d(s):
print(dump(compile(s, '<String>', 'exec', pfcf|PyCF_ONLY_AST))
当我在简单的Hello World上运行此功能时,它会吐出以下内容(格式化以便于阅读):
When I run this function on a simple Hello World, it spits out the following (formatted for easier reading):
d("print('Hello World!')")
Module(body=[Expr(value=Call(func=Name(id='print',
ctx=Load()),
args=[Str(s='Hello World!')],
keywords=[],
starargs=None,
kwargs=None))])
我能够动态生成并运行此代码-一切都很棒。
I was able to dynamically generate this code and run it - everything was great.
然后我尝试动态生成
print(len('Hello World!'))
应该很容易-只是另一个函数调用。这是我的代码动态生成的内容:
Should be pretty easy - just another function call. Here's what my code dynamically generated:
Module(body=[Expr(value=Call(func=Name(id='print',
ctx=Load()),
args=[Expr(value=Call(func=Name(id='len',
ctx=Load()),
args=[Str(s='Hello World!')],
keywords=[],
starargs=None,
kwargs=None))],
keywords=[],
starargs=None,
kwargs=None))])
运行它没有用,但是。相反,我收到此消息:
Running it didn't work, though. Instead, I got this message:
TypeError: expected some sort of expr, but got <_ast.Expr object at 0x101812c10>
所以我运行了前面提到的helper方法以查看其输出内容:
So I ran my helper method previously mentioned to see what it would output:
d("print(len('Hello World!')")
Module(body=[Expr(value=Call(func=Name(id='print',
ctx=Load()),
args=[Call(func=Name(id='len',
ctx=Load()),
args=[Str(s='Hello World!')],
keywords=[],
starargs=None,
kwargs=None)],
keywords=[],
starargs=None,
kwargs=None))])
我生成的内容(不起作用)和生成的内容(起作用)之间的区别在于,它们直接传递了 Call
到args,而我把我的包裹在 Expr
中。
The difference between what I'm generating (which doesn't work) and what it generates (which works), is that they passed Call
directly to args, whereas I wrapped mine in Expr
.
问题是,在第一行中,我需要将 Call
包装在 Expr
中。我很困惑-为什么有时有时需要将 Call
包装在 Expr
中,而不需要其他时间? Expr
似乎应该只是 Call
继承的抽象基类,但它是最上层的必需项在 Module
下。为什么?我想念些什么吗?何时需要将 Call
包装在 Expr
中以及何时可以直接使用它的规则是什么?
The problem is, in the very first line, I needed to wrap Call
in an Expr
. I'm confused - why is it sometimes necessary to wrap a Call
in an Expr
but not other times? Expr
seems like it should be just an abstract base class which Call
inherits from, but it's required at the top level right under the Module
. Why? Is there something subtle I'm missing? What are the rules for when Call
needs to be wrapped in an Expr
and when it can be used directly?
推荐答案
Expr
本身不是表达式的节点,而是表达式-statement ---即仅包含表达式的语句。这不是很明显,因为抽象语法使用三个不同的标识符 Expr
, Expression
和 expr
,所有含义都稍有不同。
Expr
is not the node for an expression per se but rather an expression-statement --- that is, a statement consisting of only an expression. This is not totally obvious because the abstract grammar uses three different identifiers Expr
, Expression
, and expr
, all meaning slightly different things.
Statement的语法允许Expr节点作为子节点,但是Expr节点的语法不允许不允许另一个Expr节点作为子节点。换句话说,您所指的 args
值应该是表达式的列表,而不是 Expr的列表
节点。请参见抽象语法的文档,其中包括:
The grammar of Statement allows an Expr node as a child, but the grammar of an Expr node doesn't allow another Expr node as a child. In other words, the args
value you are referring to is supposed to be a list of things-that-are-expressions, not a list of Expr
nodes. See the documentation of the abstract grammar, which includes:
stmt = FunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list)
| ClassDef(identifier name, expr* bases, stmt* body, expr* decorator_list)
#...
| Expr(expr value)
换句话说,可能的语句是 Expr(等等),其中
blah
与 expr
的语法相匹配。这是语法中 Expr
的唯一用法,因此,所有 Expr
都可以使用; Expr
是可能的语句,仅此而已。语法中的其他地方:
In other words, a possible statement is Expr(blah)
, where blah
is something matching the grammar of expr
. This is the only use of Expr
in the grammar, so this is all an Expr
can be; an Expr
is a possible statement and nothing else. Elsewhere in the grammar:
expr = BoolOp(boolop op, expr* values)
| BinOp(expr left, operator op, expr right)
# other stuff notably excluding Expr(...)
| Call(expr func, expr* args, keyword* keywords,
expr? starargs, expr? kwargs)
由于 Call
的 args
自变量必须与 expr * $ c相匹配$ c>,它必须是与
expr
匹配的事物的列表。但是 Expr
节点与 expr
不匹配; expr
语法匹配表达式,而不是表达式语句。
Since the args
argument of Call
must match expr*
, it must be a list of things matching expr
. But an Expr
node doesn't match expr
; the expr
grammar matches an expression, not an expression-statement.
请注意,如果您使用 eval compile
模式,它将编译一个表达式,而不是一条语句,因此 Expr
节点将不存在,并且顶级 Module
节点将替换为 Expression
:
Note that if you use the "eval" mode of compile
, it will compile an expression, not a statement, so the Expr
node will be absent, and the top-level Module
node will be replaced by Expression
:
>>> print(dump(compile('print("blah")', '<String>', 'eval', pfcf|PyCF_ONLY_AST)))
Expression(body=Call(func=Name(id='print', ctx=Load()), args=[Str(s=u'blah')], keywords=[], starargs=None, kwargs=None))
您可以看到表达式
的主体是单个表达式(即 expr
),因此 body
不是列表,而是直接设置为 Call
节点。但是,当您在 exec模式下编译时,它必须为模块及其语句创建额外的节点,而 Expr
就是这样的节点。
You can see that the body of an Expression
is a single expression (i.e., an expr
), so body
is not a list but is set directly to the Call
node. When you compile in "exec" mode, though, it has to create extra nodes for the module and its statements, and Expr
is such a node.
这篇关于什么是Python AST中的Expr?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!