ast --- 抽象語法樹 (Abstract Syntax Trees)¶
原始碼:Lib/ast.py
ast 模組可以幫助 Python 應用程式處理 Python 抽象語法文法 (abstract syntax grammar) 樹狀資料結構。抽象語法本身可能會隨著每個 Python 版本發布而改變;此模組有助於以程式化的方式來得知目前文法的面貌。
要生成抽象語法樹,可以透過將 ast.PyCF_ONLY_AST 作為旗標傳遞給內建函式 compile() 或使用此模組所提供的 parse() 輔助函式。結果將會是一個物件的樹,其類別都繼承自 ast.AST。可以使用內建的 compile() 函式將抽象語法樹編譯成 Python 程式碼物件。
抽象文法 (Abstract Grammar)¶
抽象文法目前定義如下:
-- ASDL's 4 builtin types are:
-- identifier, int, string, constant
module Python
{
mod = Module(stmt* body, type_ignore* type_ignores)
| Interactive(stmt* body)
| Expression(expr body)
| FunctionType(expr* argtypes, expr returns)
stmt = FunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list, expr? returns,
string? type_comment, type_param* type_params)
| AsyncFunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list, expr? returns,
string? type_comment, type_param* type_params)
| ClassDef(identifier name,
expr* bases,
keyword* keywords,
stmt* body,
expr* decorator_list,
type_param* type_params)
| Return(expr? value)
| Delete(expr* targets)
| Assign(expr* targets, expr value, string? type_comment)
| TypeAlias(expr name, type_param* type_params, expr value)
| AugAssign(expr target, operator op, expr value)
-- 'simple' indicates that we annotate simple name without parens
| AnnAssign(expr target, expr annotation, expr? value, int simple)
-- use 'orelse' because else is a keyword in target languages
| For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
| AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
| While(expr test, stmt* body, stmt* orelse)
| If(expr test, stmt* body, stmt* orelse)
| With(withitem* items, stmt* body, string? type_comment)
| AsyncWith(withitem* items, stmt* body, string? type_comment)
| Match(expr subject, match_case* cases)
| Raise(expr? exc, expr? cause)
| Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
| TryStar(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
| Assert(expr test, expr? msg)
| Import(alias* names)
| ImportFrom(identifier? module, alias* names, int? level)
| Global(identifier* names)
| Nonlocal(identifier* names)
| Expr(expr value)
| Pass | Break | Continue
-- col_offset is the byte offset in the utf8 string the parser uses
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
-- BoolOp() can use left & right?
expr = BoolOp(boolop op, expr* values)
| NamedExpr(expr target, expr value)
| BinOp(expr left, operator op, expr right)
| UnaryOp(unaryop op, expr operand)
| Lambda(arguments args, expr body)
| IfExp(expr test, expr body, expr orelse)
| Dict(expr?* keys, expr* values)
| Set(expr* elts)
| ListComp(expr elt, comprehension* generators)
| SetComp(expr elt, comprehension* generators)
| DictComp(expr key, expr value, comprehension* generators)
| GeneratorExp(expr elt, comprehension* generators)
-- the grammar constrains where yield expressions can occur
| Await(expr value)
| Yield(expr? value)
| YieldFrom(expr value)
-- need sequences for compare to distinguish between
-- x < 4 < 3 and (x < 4) < 3
| Compare(expr left, cmpop* ops, expr* comparators)
| Call(expr func, expr* args, keyword* keywords)
| FormattedValue(expr value, int conversion, expr? format_spec)
| Interpolation(expr value, constant str, int conversion, expr? format_spec)
| JoinedStr(expr* values)
| TemplateStr(expr* values)
| Constant(constant value, string? kind)
-- the following expression can appear in assignment context
| Attribute(expr value, identifier attr, expr_context ctx)
| Subscript(expr value, expr slice, expr_context ctx)
| Starred(expr value, expr_context ctx)
| Name(identifier id, expr_context ctx)
| List(expr* elts, expr_context ctx)
| Tuple(expr* elts, expr_context ctx)
-- can appear only in Subscript
| Slice(expr? lower, expr? upper, expr? step)
-- col_offset is the byte offset in the utf8 string the parser uses
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
expr_context = Load | Store | Del
boolop = And | Or
operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift
| RShift | BitOr | BitXor | BitAnd | FloorDiv
unaryop = Invert | Not | UAdd | USub
cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn
comprehension = (expr target, expr iter, expr* ifs, int is_async)
excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
arguments = (arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs,
expr?* kw_defaults, arg? kwarg, expr* defaults)
arg = (identifier arg, expr? annotation, string? type_comment)
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
-- keyword arguments supplied to call (NULL identifier for **kwargs)
keyword = (identifier? arg, expr value)
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
-- import name with optional 'as' alias.
alias = (identifier name, identifier? asname)
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
withitem = (expr context_expr, expr? optional_vars)
match_case = (pattern pattern, expr? guard, stmt* body)
pattern = MatchValue(expr value)
| MatchSingleton(constant value)
| MatchSequence(pattern* patterns)
| MatchMapping(expr* keys, pattern* patterns, identifier? rest)
| MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns)
| MatchStar(identifier? name)
-- The optional "rest" MatchMapping parameter handles capturing extra mapping keys
| MatchAs(pattern? pattern, identifier? name)
| MatchOr(pattern* patterns)
attributes (int lineno, int col_offset, int end_lineno, int end_col_offset)
type_ignore = TypeIgnore(int lineno, string tag)
type_param = TypeVar(identifier name, expr? bound, expr? default_value)
| ParamSpec(identifier name, expr? default_value)
| TypeVarTuple(identifier name, expr? default_value)
attributes (int lineno, int col_offset, int end_lineno, int end_col_offset)
}
節點 (Node) 類別¶
- class ast.AST¶
這是所有 AST 節點類別的基礎。實際的節點類別是衍生自
Parser/Python.asdl檔案,該檔案在上方 重現。它們被定義於_ast的 C 模組中,並於ast中重新匯出。抽象文法中為每個左側符號定義了一個類別(例如
ast.stmt或ast.expr)。此外,也為每個右側的建構函式 (constructor) 定義了一個類別;這些類別繼承自左側樹的類別。例如,ast.BinOp繼承自ast.expr。對於具有替代方案(即為「和 (sums)」)的生產規則,左側類別是抽象的:僅有特定建構函式節點的實例會被建立。- _fields¶
每個具體類別都有一個屬性
_fields,它會給出所有子節點的名稱。具體類別的每個實例對於每個子節點都有一個屬性,其型別如文法中所定義。例如,
ast.BinOp實例具有型別為ast.expr的屬性left。如果這些屬性在文法中被標記為可選(使用問號),則該值可能為
None。如果屬性可以有零個或多個值(用星號標記),則這些值將表示為 Python 串列。使用compile()編譯 AST 時,所有可能的屬性都必須存在並且具有有效值。
- _field_types¶
每個具體類別上的
_field_types屬性是將欄位名稱(也在_fields中列出)對映到其型別的字典。>>> ast.TypeVar._field_types {'name': <class 'str'>, 'bound': ast.expr | None, 'default_value': ast.expr | None}
在 3.13 版被加入.
- lineno¶
- col_offset¶
- end_lineno¶
- end_col_offset¶
ast.expr和ast.stmt子類別的實例具有lineno、col_offset、end_lineno和end_col_offset屬性。lineno和end_lineno是原始文本跨度 (source text span) 的第一個和最後一個列號(1-indexed,因此第一列號是 1)以及col_offset和end_col_offset是生成節點的第一個和最後一個標記對應的 UTF-8 位元組偏移量。會記錄 UTF-8 偏移量是因為剖析器 (parser) 內部使用 UTF-8。請注意,編譯器並不需要結束位置,因此其為可選的。結束偏移量在最後一個符號之後,例如可以使用
source_line[node.col_offset : node.end_col_offset]來取得單列運算式節點 (expression node) 的原始片段。
ast.T類別的建構函式按以下方式剖析其引數:如果有位置引數,則必須與
T._fields中的項目一樣多;它們將被賦値為這些名稱的屬性。如果有關鍵字引數,它們會將相同名稱的屬性設定為給定值。
例如,要建立並填充 (populate)
ast.UnaryOp節點,你可以使用:node = ast.UnaryOp(ast.USub(), ast.Constant(5, lineno=0, col_offset=0), lineno=0, col_offset=0)
如果建構函式中省略了文法中可選的欄位,則它預設為
None。如果省略串列欄位,則預設為空串列。如果省略ast.expr_context型別的欄位,則預設為Load()。如果省略任何其他欄位,則會引發DeprecationWarning,且 AST 節點將沒有此欄位。在 Python 3.15 中,這種情況會引發錯誤。
在 3.8 版的變更: ast.Constant 類別現在用於所有常數。
在 3.9 版的變更: 以它們的值表示簡單索引,擴充切片 (slice) 則以元組 (tuple) 表示。
在 3.13 版的變更: AST node constructors were changed to provide sensible defaults for omitted
fields: optional fields now default to None, list fields default to an
empty list, and fields of type ast.expr_context default to
Load(). Previously, omitted attributes would not exist on constructed
nodes (accessing them raised AttributeError).
在 3.14 版的變更: AST 節點的 __repr__() 輸出包含節點欄位的值。
自從版本 3.8 後不推薦使用,已從版本 3.14 中移除。: 過去的 Python 版本提供了 AST 類別 ast.Num、ast.Str、ast.Bytes、ast.NameConstant 和 ast.Ellipsis,這些類別在 Python 3.8 中已被棄用。這些類別在 Python 3.14 中被移除,其功能已被 ast.Constant 取代。
在 3.9 版之後被棄用: 舊的類別 ast.Index 和 ast.ExtSlice 仍然可用,但它們將在未來的 Python 版本中刪除。同時,實例化它們會回傳不同類別的實例。
自從版本 3.13 後不推薦使用,將會自版本 3.15 中移除。: 先前版本的 Python 允許建立缺少必填欄位的 AST 節點。同樣地,AST 節點建構函式允許將任意關鍵字引數設為 AST 節點的屬性,即使它們與 AST 節點的任何欄位都不匹配。此行為已被棄用,並將在 Python 3.15 中刪除。
備註
這裡顯示的特定節點類別的描述最初是從出色的 Green Tree Snakes 專案和所有貢獻者那裡改編而來的。
根節點¶
- class ast.Module(body, type_ignores)¶
一個 Python 模組,與檔案輸入 一樣。由
ast.parse()在預設的"exec"mode 下生成的節點型別。type_ignores是模組的忽略型別註解的list;有關更多詳細資訊,請參閱ast.parse()。>>> print(ast.dump(ast.parse('x = 1'), indent=4)) Module( body=[ Assign( targets=[ Name(id='x', ctx=Store())], value=Constant(value=1))])
- class ast.Expression(body)¶
單個 Python 運算式輸入。當 mode 是
"eval"時節點型別由ast.parse()生成。body是單個節點,是運算式型別的其中之一。>>> print(ast.dump(ast.parse('123', mode='eval'), indent=4)) Expression( body=Constant(value=123))
- class ast.Interactive(body)¶
單個互動式輸入,和互動模式中所述的相似。當 mode 是
"single"時節點型別由ast.parse()生成。body是陳述式節點 (statement nodes) 的list。>>> print(ast.dump(ast.parse('x = 1; y = 2', mode='single'), indent=4)) Interactive( body=[ Assign( targets=[ Name(id='x', ctx=Store())], value=Constant(value=1)), Assign( targets=[ Name(id='y', ctx=Store())], value=Constant(value=2))])
- class ast.FunctionType(argtypes, returns)¶
函式的舊式型別註解的表示法,因為 3.5 之前的 Python 版本不支援 PEP 484 註釋。當 mode 是
"func_type"時節點型別由ast.parse()生成。這種型別的註解看起來像這樣:
def sum_two_number(a, b): # type: (int, int) -> int return a + b
argtypes是運算式節點的