What is an Expr in Python AST?

前端 未结 2 1108
盖世英雄少女心
盖世英雄少女心 2021-01-06 07:36

I\'m working on dynamically generating code in Python.

To aid with this, I wrote a helper method which takes in a string of Python code and dumps out the AST. Here\'

相关标签:
2条回答
  • 2021-01-06 07:56

    Agreeing with what @BreBarn said:

    "When an expression, such as a function call, appears as a statement by itself (an expression statement), with its return value not used or stored, it is wrapped in this container."

    Since you're using the result of the len function to print, it's not technically an Expression, in the AST sense.

    See this for more info: https://greentreesnakes.readthedocs.org/en/latest/nodes.html#expressions

    0 讨论(0)
  • 2021-01-06 07:58

    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.

    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)
    

    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)
    

    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.

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

    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.

    0 讨论(0)
提交回复
热议问题