ast
--- 抽象語法樹 (Abstract Syntax Trees)¶原始碼:Lib/ast.py
ast
模組可以幫助 Python 應用程式處理 Python 抽象語法文法 (abstract syntax grammar) 樹狀資料結構。抽象語法本身可能會隨著每個 Python 版本發布而改變;此模組有助於以程式化的方式來得知目前文法的面貌。
要生成抽象語法樹,可以透過將 ast.PyCF_ONLY_AST
作為旗標傳遞給內建函式 compile()
或使用此模組所提供的 parse()
輔助函式。結果將會是一個物件的樹,其類別都繼承自 ast.AST
。可以使用內建的 compile()
函式將抽象語法樹編譯成 Python 程式碼物件。
抽象文法目前定義如下:
-- 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)
| JoinedStr(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)
}
這是所有 AST 節點類別的基礎。實際的節點類別是衍生自 Parser/Python.asdl
檔案,該檔案在上方 重現。它們被定義於 _ast
的 C 模組中,並於 ast
中重新匯出。
抽象文法中為每個左側符號定義了一個類別(例如 ast.stmt
或 ast.expr
)。此外,也為每個右側的建構函式 (constructor) 定義了一個類別;這些類別繼承自左側樹的類別。例如,ast.BinOp
繼承自 ast.expr
。對於具有替代方案(即為「和 (sums)」)的生產規則,左側類別是抽象的:僅有特定建構函式節點的實例會被建立。
每個具體類別都有一個屬性 _fields
,它會給出所有子節點的名稱。
具體類別的每個實例對於每個子節點都有一個屬性,其型別如文法中所定義。例如,ast.BinOp
實例具有型別為 ast.expr
的屬性 left
。
如果這些屬性在文法中被標記為可選(使用問號),則該值可能為 None
。如果屬性可以有零個或多個值(用星號標記),則這些值將表示為 Python 串列。使用 compile()
編譯 AST 時,所有可能的屬性都必須存在並且具有有效值。
每個具體類別上的 _field_types
屬性是將欄位名稱(也在 _fields
中列出)對映到其型別的字典。
>>> ast.TypeVar._field_types
{'name': <class 'str'>, 'bound': ast.expr | None, 'default_value': ast.expr | None}
在 3.13 版被加入.
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.8 版之後被棄用: 舊的類別 ast.Num
、ast.Str
、ast.Bytes
、ast.NameConstant
和 ast.Ellipsis
仍然可用,但它們將在未來的 Python 釋出版本中移除。與此同時,實例化它們將回傳不同類別的實例。
在 3.9 版之後被棄用: 舊的類別 ast.Index
和 ast.ExtSlice
仍然可用,但它們將在未來的 Python 版本中刪除。同時,實例化它們會回傳不同類別的實例。
Deprecated since version 3.13, will be removed in version 3.15: 先前版本的 Python 允許建立缺少必填欄位的 AST 節點。同樣地,AST 節點建構函式允許將任意關鍵字引數設為 AST 節點的屬性,即使它們與 AST 節點的任何欄位都不匹配。此行為已被棄用,並將在 Python 3.15 中刪除。
備註
這裡顯示的特定節點類別的描述最初是從出色的 Green Tree Snakes 專案和所有貢獻者那裡改編而來的。
一個 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))])
單個 Python 運算式輸入。當 mode 是 "eval"
時節點型別由 ast.parse()
生成。
body
是單個節點,是運算式型別的其中之一。
>>> print(ast.dump(ast.parse('123', mode='eval'), indent=4))
Expression(
body=Constant(value=123))
單個互動式輸入,和互動模式中所述的相似。當 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))])
函式的舊式型別註解的表示法,因為 3.5 之前的 Python 版本不支援 PEP 484 註釋。當 mode 是 "func_type"
時節點型別由 ast.parse()
生成。
這種型別的註解看起來像這樣:
def sum_two_number(a, b):
# type: (int, int) -> int
return a + b
returns
是單個運算式節點。
>>> print(ast.dump(ast.parse('(int, str) -> List[int]', mode='func_type'), indent=4))
FunctionType(
argtypes=[
Name(id='int', ctx=Load()),
Name(id='str', ctx=Load())],
returns=Subscript(
value=Name(id='List', ctx=Load()),
slice=Name(id='int', ctx=Load()),
ctx=Load()))
在 3.8 版被加入.
一個常數值。Constant
文本的 value
屬性包含它所代表的 Python 物件。表示的值可以是簡單型別,例如數字、字串或 None
,但如果它們的所有元素都是常數,也可以是不可變的 (immutable) 容器型別(元組和凍結集合 (frozensets))。
>>> print(ast.dump(ast.parse('123', mode='eval'), indent=4))
Expression(
body=Constant(value=123))
表示 f 字串 (f-string) 中的單個格式化欄位的節點。如果字串包含單個格式欄位並且沒有其他內容,則可以隔離 (isolate) 該節點,否則它將出現在 JoinedStr
中。
value
為任何運算式節點(例如文字、變數或函式呼叫)。
conversion
是一個整數:
-1: 無格式化
115: !s
字串格式化
114:!r
重複格式化化
97: !a
ascii 格式化
format_spec
是一個 JoinedStr
節點,表示值的格式,若未指定格式則為 None
。conversion
和 format_spec
可以同時設定。
一個 f 字串,包含一系列 FormattedValue
和 Constant
節點。
>>> print(ast.dump(ast.parse('f"sin({a}) is {sin(a):.3}"', mode='eval'), indent=4))
Expression(
body=JoinedStr(
values=[
Constant(value='sin('),
FormattedValue(
value=Name(id='a', ctx=Load()),
conversion=-1),
Constant(value=') is '),
FormattedValue(
value=Call(
func=Name(id='sin', ctx=Load()),
args=[
Name(id='a', ctx=Load())]),
conversion=-1,
format_spec=JoinedStr(
values=[
Constant(value='.3')]))]))
串列或元組。elts
保存表示元素的節點串列。如果容器是賦值目標(即 (x,y)=something
),則 ctx
是 Store
,否則是 Load
。
>>> print(ast.dump(ast.parse('[1, 2, 3]', mode='eval'), indent=4))
Expression(
body=List(
elts=[
Constant(value=1),
Constant(value=2),
Constant(value=3)],
ctx=Load()))
>>> print(ast.dump(ast.parse('(1, 2, 3)', mode='eval'), indent=4))
Expression(
body=Tuple(
elts=[
Constant(value=1),
Constant(value=2),
Constant(value=3)],
ctx=Load()))
一個集合。elts
保存表示集合之元素的節點串列。
>>> print(ast.dump(ast.parse('{1, 2, 3}', mode='eval'), indent=4))
Expression(
body=Set(
elts=[
Constant(value=1),
Constant(value=2),
Constant(value=3)]))
一個字典 (dictionary)。keys
和 values
分別按匹配順序保存表示鍵和值的節點串列(為呼叫 dictionary.keys()
和 dictionary.values()
時將回傳的內容)。
當使用字典文本進行字典解包 (unpack) 時,要擴充的運算式位於 values
串列中,在 keys
中的相應位置有一個 None
。
>>> print(ast.dump(ast.parse('{"a":1, **d}', mode='eval'), indent=4))
Expression(
body=Dict(
keys=[
Constant(value='a'),
None],
values=[
Constant(value=1),
Name(id='d', ctx=Load())]))
一個變數名稱。id
將名稱以字串形式保存,且 ctx
是以下型別之一。
變數參照可用於載入變數的值、為其分配新值或刪除它。變數參照被賦予情境 (context) 來區分這些情況。
>>> print(ast.dump(ast.parse('a'), indent=4))
Module(
body=[
Expr(
value=Name(id='a', ctx=Load()))])
>>> print(ast.dump(ast.parse('a = 1'), indent=4))
Module(
body=[
Assign(
targets=[
Name(id='a', ctx=Store())],
value=Constant(value=1))])
>>> print(ast.dump(ast.parse('del a'), indent=4))
Module(
body=[
Delete(
targets=[
Name(id='a', ctx=Del())])])
一個 *var
變數參照。value
保存變數,通常是一個 Name
節點。在使用 *args
建置 Call
節點時必須使用此型別。
>>> print(ast.dump(ast.parse('a, *b = it'), indent=4))
Module(
body=[
Assign(
targets=[
Tuple(
elts=[
Name(id='a', ctx=Store()),
Starred(
value=Name(id='b', ctx=Store()),
ctx=Store())],
ctx=Store())],
value=Name(id='it', ctx=Load()))])
當運算式(例如函式呼叫)本身作為陳述式出現且未使用或儲存其回傳值時,它將被包裝在此容器中。value
保存此區段 (section) 中的一個其他節點:Constant
、Name
、Lambda
、Yield
或 YieldFrom
>>> print(ast.dump(ast.parse('-a'), indent=4))
Module(
body=[
Expr(
value=UnaryOp(
op=USub(),
operand=Name(id='a', ctx=Load())))])
一元運算 (unary operation)。op
是運算子,operand
是任何運算式節點。
一元運算子標記。 Not
是 not
關鍵字、Invert
是 ~
運算子。
>>> print(ast.dump(ast.parse('not x', mode='eval'), indent=4))
Expression(
body=UnaryOp(
op=Not(),
operand=Name(id='x', ctx=Load())))
二元運算 (binary operation)(如加法或除法)。 op
是運算子、left
和 right
是任意運算式節點。
>>> print(ast.dump(ast.parse('x + y', mode='eval'), indent=4))
Expression(
body=BinOp(
left=Name(id='x', ctx=Load()),
op=Add(),
right=Name(id='y', ctx=Load())))
二元運算子 token。
布林運算 'or' 或 'and'。op
是 Or
或 And
。values
是有所涉及的值。使用同一運算子的連續操作(例如 a or b or c
)會被折疊為具有多個值的一個節點。
這不包括 not
,它是一個 UnaryOp
。
>>> print(ast.dump(ast.parse('x or y', mode='eval'), indent=4))
Expression(
body=BoolOp(
op=Or(),
values=[
Name(id='x', ctx=Load()),
Name(id='y', ctx=Load())]))
兩個或多個值的比較。left
是比較中的第一個值、ops
是運算子串列、comparators
是要比較的第一個元素之後值的串列。
>>> print(ast.dump(ast.parse('1 <= a < 10', mode='eval'), indent=4))
Expression(
body=Compare(
left=Constant(value=1),
ops=[
LtE(),
Lt()],
comparators=[
Name(id='a', ctx=Load()),
Constant(value=10)]))
比較運算子 token。
一個函式呼叫。func
是該函式,通常是一個 Name
或 Attribute
物件。而在引數中:
args
保存按位置傳遞的引數串列。
keywords
保存一個 keyword
物件串列,表示透過關鍵字傳遞的引數。
args
和 keywords
引數是可選的,預設為空串列。
>>> print(ast.dump(ast.parse('func(a, b=c, *d, **e)', mode='eval'), indent=4))
Expression(
body=Call(
func=Name(id='func', ctx=Load()),
args=[
Name(id='a', ctx=Load()),
Starred(
value=Name(id='d', ctx=Load()),
ctx=Load())],
keywords=[
keyword(
arg='b',
value=Name(id='c', ctx=Load())),
keyword(
value=Name(id='e', ctx=Load()))]))
函式呼叫或類別定義的關鍵字引數。arg
是參數名稱的原始字串,value
是要傳入的節點。
像是 a if b else c
之類的運算式。每個欄位都保存一個節點,因此在以下範例中,所有三個都是 Name
節點。
>>> print(ast.dump(ast.parse('a if b else c', mode='eval'), indent=4))
Expression(
body=IfExp(
test=Name(id='b', ctx=Load()),
body=Name(id='a', ctx=Load()),
orelse=Name(id='c', ctx=Load())))
屬性的存取,例如 d.keys
。value
是一個節點,通常是一個 Name
。attr
是一個屬性名稱的字串,ctx
根據屬性的作用方式可能是 Load
、Store
或 Del
。
>>> print(ast.dump(ast.parse('snake.colour', mode='eval'), indent=4))
Expression(
body=Attribute(
value=Name(id='snake', ctx=Load()),
attr='colour',
ctx=Load()))
一個附名運算式 (named expression)。該 AST 節點由賦值運算式運算子(也稱為海象運算子)產生。相對於 Assign
節點之第一個引數可為多個節點,在這種情況下 target
和 value
都必須是單個節點。
>>> print(ast.dump(ast.parse('(x := 4)', mode='eval'), indent=4))
Expression(
body=NamedExpr(
target=Name(id='x', ctx=Store()),
value=Constant(value=4)))
在 3.8 版被加入.
一個下標,例如 l[1]
。value
是下標物件(通常是序列或對映)。slice
是索引、切片或鍵。它可以是一個 Tuple
並包含一個 Slice
。根據下標執行的操作不同,ctx
可以是 Load
、Store
或 Del
。
>>> print(ast.dump(ast.parse('l[1:2, 3]', mode='eval'), indent=4))
Expression(
body=Subscript(
value=Name(id='l', ctx=Load()),
slice=Tuple(
elts=[
Slice(
lower=Constant(value=1),
upper=Constant(value=2)),
Constant(value=3)],
ctx=Load()),
ctx=Load()))
常規切片(形式為 lower:upper
或 lower:upper:step
)。只能直接或者或者作為 Tuple
的元素出現在 Subscript
的 slice 欄位內。
>>> print(ast.dump(ast.parse('l[1:2]', mode='eval'), indent=4))
Expression(
body=Subscript(
value=Name(id='l', ctx=Load()),
slice=Slice(
lower=Constant(value=1),
upper=Constant(value=2)),
ctx=Load()))
串列和集合綜合運算、生成器運算式和字典綜合運算。elt
(或 key
和 value
)是單個節點,表示各個項目會被求值 (evaluate) 的部分。
generators
是一個 comprehension
節點的串列。
>>> print(ast.dump(
... ast.parse('[x for x in numbers]', mode='eval'),
... indent=4,
... ))
Expression(
body=ListComp(
elt=Name(id='x', ctx=Load()),
generators=[
comprehension(
target=Name(id='x', ctx=Store()),
iter=Name(id='numbers', ctx=Load()),
is_async=0)]))
>>> print(ast.dump(
... ast.parse('{x: x**2 for x in numbers}', mode='eval'),
... indent=4,
... ))
Expression(
body=DictComp(
key=Name(id='x', ctx=Load()),
value=BinOp(
left=Name(id='x', ctx=Load()),
op=Pow(),
right=Constant(value=2)),
generators=[
comprehension(
target=Name(id='x', ctx=Store()),
iter=Name(id='numbers', ctx=Load()),
is_async=0)]))
>>> print(ast.dump(
... ast.parse('{x for x in numbers}', mode='eval'),
... indent=4,
... ))
Expression(
body=SetComp(
elt=Name(id='x', ctx=Load()),
generators=[
comprehension(
target=Name(id='x', ctx=Store()),
iter=Name(id='numbers', ctx=Load()),
is_async=0)]))
綜合運算中的一個 for
子句。target
是用於每個元素的參照 - 通常是 Name
或 Tuple
節點。iter
是要疊代的物件。ifs
是測試運算式的串列:每個 for
子句可以有多個 ifs
。
is_async
表示綜合運算式是非同步的(使用 async for
而不是 for
)。該值為整數(0 或 1)。
>>> print(ast.dump(ast.parse('[ord(c) for line in file for c in line]', mode='eval'),
... indent=4)) # Multiple comprehensions in one.
Expression(
body=ListComp(
elt=Call(
func=Name(id='ord', ctx=Load()),
args=[
Name(id='c', ctx=Load())]),
generators=[
comprehension(
target=Name(id='line', ctx=Store()),
iter=Name(id='file', ctx=Load()),
is_async=0),
comprehension(
target=Name(id='c', ctx=Store()),
iter=Name(id='line', ctx=Load()),
is_async=0)]))
>>> print(ast.dump(ast.parse('(n**2 for n in it if n>5 if n<10)', mode='eval'),
... indent=4)) # generator comprehension
Expression(
body=GeneratorExp(
elt=BinOp(
left=Name(id='n', ctx=Load()),
op=Pow(),
right=Constant(value=2)),
generators=[
comprehension(
target=Name(id='n', ctx=Store()),
iter=Name(id='it', ctx=Load()),
ifs=[
Compare(
left=Name(id='n', ctx=Load()),
ops=[
Gt()],
comparators=[
Constant(value=5)]),
Compare(
left=Name(id='n', ctx=Load()),
ops=[
Lt()],
comparators=[
Constant(value=10)])],
is_async=0)]))
>>> print(ast.dump(ast.parse('[i async for i in soc]', mode='eval'),
... indent=4)) # Async comprehension
Expression(
body=ListComp(
elt=Name(id='i', ctx=Load()),
generators=[
comprehension(
target=Name(id='i', ctx=Store()),
iter=Name(id='soc', ctx=Load()),
is_async=1)]))
一個賦值。targets
是節點串列,value
是單個節點。
targets
中的多個節點表示為每個節點分配相同的值。解包是透過在 targets
中放置一個 Tuple
或 List
來表示的。
type_comment
是一個可選字串,其中的註解為型別註釋。
>>> print(ast.dump(ast.parse('a = b = 1'), indent=4)) # Multiple assignment
Module(
body=[
Assign(
targets=[
Name(id='a', ctx=Store()),
Name(id='b', ctx=Store())],
value=Constant(value=1))])
>>> print(ast.dump(ast.parse('a,b = c'), indent=4)) # Unpacking
Module(
body=[
Assign(
targets=[
Tuple(
elts=[
Name(id='a', ctx=Store()),
Name(id='b', ctx=Store())],
ctx=Store())],
value=Name(id='c', ctx=Load()))])
帶有型別註釋的賦值。target
是單個節點,可以是 Name
、Attribute
或 Subscript
。annotation
是註釋,例如 Constant
或 Name
節點。value
是單個可選節點。
simple
總會是 0(表示一個「複雜」目標)或 1(表示一個「簡單」目標)。一個「簡單」目標僅包含一個 Name
節點,且不出現在括號之間;所有其他目標都被視為是複雜的。只有簡單目標會出現在模組和類別的 __annotations__
字典中。
>>> print(ast.dump(ast.parse('c: int'), indent=4))
Module(
body=[
AnnAssign(
target=Name(id='c', ctx=Store()),
annotation=Name(id='int', ctx=Load()),
simple=1)])
>>> print(ast.dump(ast.parse('(a): int = 1'), indent=4)) # Annotation with parenthesis
Module(
body=[
AnnAssign(
target=Name(id='a', ctx=Store()),
annotation=Name(id='int', ctx=Load()),
value=Constant(value=1),
simple=0)])
>>> print(ast.dump(ast.parse('a.b: int'), indent=4)) # Attribute annotation
Module(
body=[
AnnAssign(
target=Attribute(
value=Name(id='a', ctx=Load()),
attr='b',
ctx=Store()),
annotation=Name(id='int', ctx=Load()),
simple=0)])
>>> print(ast.dump(ast.parse('a[1]: int'), indent=4)) # Subscript annotation
Module(
body=[
AnnAssign(
target=Subscript(
value=Name(id='a', ctx=Load()),
slice=Constant(value=1),
ctx=Store()),
annotation=Name(id='int', ctx=Load()),
simple=0)])
增加賦值 (augmented assignment),例如 a += 1
。在下面的範例中,target
是 x
的 Name
節點(帶有 Store
情境),op
是 Add
,value
是一個值為 1 的 Constant
。
與 Assign
的目標不同,target
屬性不能屬於 Tuple
或 List
類別。
>>> print(ast.dump(ast.parse('x += 2'), indent=4))
Module(
body=[
AugAssign(
target=Name(id='x', ctx=Store()),
op=Add(),
value=Constant(value=2))])
一個 raise
陳述式。exc
是要引發的例外物件,通常是 Call
或 Name
,若是獨立的 raise
則為 None
。cause
是 raise x from y
中的可選部分 y
。
>>> print(ast.dump(ast.parse('raise x from y'), indent=4))
Module(
body=[
Raise(
exc=Name(id='x', ctx=Load()),
cause=Name(id='y', ctx=Load()))])
一個斷言 (assertion)。test
保存條件,例如 Compare
節點。msg
保存失敗訊息。
>>> print(ast.dump(ast.parse('assert x,y'), indent=4))
Module(
body=[
Assert(
test=Name(id='x', ctx=Load()),
msg=Name(id='y', ctx=Load()))])
代表一個 del
陳述式。targets
是節點串列,例如 Name
、Attribute
或 Subscript
節點。
>>> print(ast.dump(ast.parse('del x,y,z'), indent=4))
Module(
body=[
Delete(
targets=[
Name(id='x', ctx=Del()),
Name(id='y', ctx=Del()),
Name(id='z', ctx=Del())])])
一個 pass
陳述式。
>>> print(ast.dump(ast.parse('pass'), indent=4))
Module(
body=[
Pass()])
透過 type
陳述式建立的型別別名 (type alias)。name
是別名的名稱、type_params
是型別參數 (type parameter) 的串列、value
是型別別名的值。
>>> print(ast.dump(ast.parse('type Alias = int'), indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Alias', ctx=Store()),
value=Name(id='int', ctx=Load()))])
在 3.12 版被加入.
其他僅適用於函式或迴圈內部的陳述式將在其他部分中描述。
一個 import 陳述式。names
是 alias
節點的串列。
>>> print(ast.dump(ast.parse('import x,y,z'), indent=4))
Module(
body=[
Import(
names=[
alias(name='x'),
alias(name='y'),
alias(name='z')])])
代表 from x import y
。module
是 'from' 名稱的原始字串,前面沒有任何的點 (dot),或者對於諸如 from . import foo
之類的陳述式則為 None
。level
是一個整數,保存相對引入的級別(0 表示絕對引入)。
>>> print(ast.dump(ast.parse('from y import x,y,z'), indent=4))
Module(
body=[
ImportFrom(
module='y',
names=[
alias(name='x'),
alias(name='y'),
alias(name='z')],
level=0)])
這兩個參數都是名稱的原始字串。如果要使用常規名稱,asname
可以為 None
。
>>> print(ast.dump(ast.parse('from ..foo.bar import a as b, c'), indent=4))
Module(
body=[
ImportFrom(
module='foo.bar',
names=[
alias(name='a', asname='b'),
alias(name='c')],
level=2)])
備註
諸如 else
之類的可選子句如果不存在,則將被儲存為空串列。
一個 if
陳述式。test
保存單個節點,例如 Compare
節點。body
和 orelse
各自保存一個節點串列。
elif
子句在 AST 中沒有特殊表示,而是在前一個子句的 orelse
部分中作為額外的 If
節點出現。
>>> print(ast.dump(ast.parse("""
... if x:
... ...
... elif y:
... ...
... else:
... ...
... """), indent=4))
Module(
body=[
If(
test=Name(id='x', ctx=Load()),
body=[
Expr(
value=Constant(value=Ellipsis))],
orelse=[
If(
test=Name(id='y', ctx=Load()),
body=[
Expr(
value=Constant(value=Ellipsis))],
orelse=[
Expr(
value=Constant(value=Ellipsis))])])])
一個 for
迴圈。 target
保存迴圈賦予的變數,為單個 Name
、Tuple
、List
、Attribute
或 Subscript
節點。iter
保存要迴圈跑過的項目,也為單個節點。body
和 orelse
包含要執行的節點串列。如果迴圈正常完成,則執行 orelse
中的內容,而不是透過 break
陳述式執行。
type_comment
是一個可選字串,其中的註解為型別註釋。
>>> print(ast.dump(ast.parse("""
... for x in y:
... ...
... else:
... ...
... """), indent=4))
Module(
body=[
For(
target=Name(id='x', ctx=Store()),
iter=Name(id='y', ctx=Load()),
body=[
Expr(
value=Constant(value=Ellipsis))],
orelse=[
Expr(
value=Constant(value=Ellipsis))])])
一個 while
迴圈。test
保存條件,例如 Compare
節點。
>>> print(ast.dump(ast.parse("""
... while x:
... ...
... else:
... ...
... """), indent=4))
Module(
body=[
While(
test=Name(id='x', ctx=Load()),
body=[
Expr(
value=Constant(value=Ellipsis))],
orelse=[
Expr(
value=Constant(value=Ellipsis))])])
break
和 continue
陳述式。
>>> print(ast.dump(ast.parse("""\
... for a in b:
... if a > 5:
... break
... else:
... continue
...
... """), indent=4))
Module(
body=[
For(
target=Name(id='a', ctx=Store()),
iter=Name(id='b', ctx=Load()),
body=[
If(
test=Compare(
left=Name(id='a', ctx=Load()),
ops=[
Gt()],
comparators=[
Constant(value=5)]),
body=[
Break()],
orelse=[
Continue()])])])
try
區塊。除 handlers
是 ExceptHandler
節點的串列外,其他所有屬性都是要執行之節點的串列。
>>> print(ast.dump(ast.parse("""
... try:
... ...
... except Exception:
... ...
... except OtherException as e:
... ...
... else:
... ...
... finally:
... ...
... """), indent=4))
Module(
body=[
Try(
body=[
Expr(
value=Constant(value=Ellipsis))],
handlers=[
ExceptHandler(
type=Name(id='Exception', ctx=Load()),
body=[
Expr(
value=Constant(value=Ellipsis))]),
ExceptHandler(
type=Name(id='OtherException', ctx=Load()),
name='e',
body=[
Expr(
value=Constant(value=Ellipsis))])],
orelse=[
Expr(
value=Constant(value=Ellipsis))],
finalbody=[
Expr(
value=Constant(value=Ellipsis))])])
try
區塊,後面跟著 except*
子句。這些屬性與 Try
相同,但是 handlers
中的 ExceptHandler
節點被直譯 (interpret) 為 except*
區塊而不是 except
。
>>> print(ast.dump(ast.parse("""
... try:
... ...
... except* Exception:
... ...
... """), indent=4))
Module(
body=[
TryStar(
body=[
Expr(
value=Constant(value=Ellipsis))],
handlers=[
ExceptHandler(
type=Name(id='Exception', ctx=Load()),
body=[
Expr(
value=Constant(value=Ellipsis))])])])
在 3.11 版被加入.
單個 except
子句。type
是會被匹配的例外型別,通常是一個 Name
節點(或者 None
表示會捕捉到所有例外的 except:
子句)。name
是用於保存例外的名稱之原始字串,如果子句沒有 as foo
,則為 None
。body
是節點串列。
>>> print(ast.dump(ast.parse("""\
... try:
... a + 1
... except TypeError:
... pass
... """), indent=4))
Module(
body=[
Try(
body=[
Expr(
value=BinOp(
left=Name(id='a', ctx=Load()),
op=Add(),
right=Constant(value=1)))],
handlers=[
ExceptHandler(
type=Name(id='TypeError', ctx=Load()),
body=[
Pass()])])])
一個 with
區塊。items
是表示情境管理器的 withitem
節點串列,body
是情境內的縮進區塊。
type_comment
是一個可選字串,其中的註解為型別註釋。
with
區塊中的單個情境管理器。context_expr
是情境管理器,通常是一個 Call
節點。Optional_vars
是 as foo
部分的 Name
、Tuple
或 List
,或者如果不使用則為 None
。
>>> print(ast.dump(ast.parse("""\
... with a as b, c as d:
... something(b, d)
... """), indent=4))
Module(
body=[
With(
items=[
withitem(
context_expr=Name(id='a', ctx=Load()),
optional_vars=Name(id='b', ctx=Store())),
withitem(
context_expr=Name(id='c', ctx=Load()),
optional_vars=Name(id='d', ctx=Store()))],
body=[
Expr(
value=Call(
func=Name(id='something', ctx=Load()),
args=[
Name(id='b', ctx=Load()),
Name(id='d', ctx=Load())]))])])
一個 match
陳述式。subject
保存匹配的主題(與案例匹配的物件),cases
包含具有不同案例的 match_case
節點的可疊代物件。
在 3.10 版被加入.
match
陳述式中的單個案例模式。pattern
包含主題將與之匹配的匹配模式。請注意,為模式生成的 AST
節點與為運算式生成的節點不同,即使它們共享相同的語法。
guard
屬性包含一個運算式,如果模式與主題匹配,則將對該運算式求值。
body
包含一個節點串列,如果模式匹配並且為防護運算式 (guard expression) 的求值 (evaluate) 結果為真,則會執行該節點串列。
>>> print(ast.dump(ast.parse("""
... match x:
... case [x] if x>0:
... ...
... case tuple():
... ...
... """), indent=4))
Module(
body=[
Match(
subject=Name(id='x', ctx=Load()),
cases=[
match_case(
pattern=MatchSequence(
patterns=[
MatchAs(name='x')]),
guard=Compare(
left=Name(id='x', ctx=Load()),
ops=[
Gt()],
comparators=[
Constant(value=0)]),
body=[
Expr(
value=Constant(value=Ellipsis))]),
match_case(
pattern=MatchClass(
cls=Name(id='tuple', ctx=Load())),
body=[
Expr(
value=Constant(value=Ellipsis))])])])
在 3.10 版被加入.
以相等性進行比較的匹配文本或值的模式。value
是一個運算式節點。允許值節點受到匹配陳述式文件中所述的限制。如果匹配主題等於求出值,則此模式成功。
>>> print(ast.dump(ast.parse("""
... match x:
... case "Relevant":
... ...
... """), indent=4))
Module(
body=[
Match(
subject=Name(id='x', ctx=Load()),
cases=[
match_case(
pattern=MatchValue(
value=Constant(value='Relevant')),
body=[
Expr(
value=Constant(value=Ellipsis))])])])
在 3.10 版被加入.
按識別性 (identity) 進行比較的匹配文本模式。value
是要與 None
、True
或 False
進行比較的單例 (singleton)。如果匹配主題是給定的常數,則此模式成功。
>>> print(ast.dump(ast.parse("""
... match x:
... case None:
... ...
... """), indent=4))
Module(
body=[
Match(
subject=Name(id='x', ctx=Load()),
cases=[
match_case(
pattern=MatchSingleton(value=None),
body=[
Expr(
value=Constant(value=Ellipsis))])])])
在 3.10 版被加入.
匹配序列模式。如果主題是一個序列,patterns
包含與主題元素匹配的模式。如果子模式之一是 MatchStar
節點,則匹配可變長度序列,否則匹配固定長度序列。
>>> print(ast.dump(ast.parse("""
... match x:
... case [1, 2]:
... ...
... """), indent=4))
Module(
body=[
Match(
subject=Name(id='x', ctx=Load()),
cases=[
match_case(
pattern=MatchSequence(
patterns=[
MatchValue(
value=Constant(value=1)),
MatchValue(
value=Constant(value=2))]),
body=[
Expr(
value=Constant(value=Ellipsis))])])])
在 3.10 版被加入.
以可變長度匹配序列模式匹配序列的其餘部分。如果 name
不是 None
,則如果整體序列模式成功,則包含其餘序列元素的串列將綁定到該名稱。
>>> print(ast.dump(ast.parse("""
... match x:
... case [1, 2, *rest]:
... ...
... case [*_]:
... ...
... """), indent=4))
Module(
body=[
Match(
subject=Name(id='x', ctx=Load()),
cases=[
match_case(
pattern=MatchSequence(
patterns=[
MatchValue(
value=Constant(value=1)),
MatchValue(
value=Constant(value=2)),
MatchStar(name='rest')]),
body=[
Expr(
value=Constant(value=Ellipsis))]),
match_case(
pattern=MatchSequence(
patterns=[
MatchStar()]),
body=[
Expr(
value=Constant(value=Ellipsis))])])])
在 3.10 版被加入.
匹配對映模式。keys
是運算式節點的序列。patterns
是相應的模式節點序列。rest
是一個可選名稱,可以指定它來捕獲剩餘的對映元素。允許的鍵運算式受到匹配陳述式文件中所述的限制。
如果主題是對映,所有求值出的鍵運算式都存在於對映中,並且與每個鍵對應的值與相應的子模式匹配,則此模式成功。如果 rest
不是 None
,則如果整體對映模式成功,則包含其餘對映元素的字典將綁定到該名稱。
>>> print(ast.dump(ast.parse("""
... match x:
... case {1: _, 2: _}:
... ...
... case {**rest}:
... ...
... """), indent=4))
Module(
body=[
Match(
subject=Name(id='x', ctx=Load()),
cases=[
match_case(
pattern=MatchMapping(
keys=[
Constant(value=1),
Constant(value=2)],
patterns=[
MatchAs(),
MatchAs()]),
body=[
Expr(
value=Constant(value=Ellipsis))]),
match_case(
pattern=MatchMapping(rest='rest'),
body=[
Expr(
value=Constant(value=Ellipsis))])])])
在 3.10 版被加入.
匹配類別模式。cls
是一個給定要匹配的名義類別 (nominal class) 的運算式。patterns
是要與類別定義的模式匹配屬性序列進行匹配的模式節點序列。kwd_attrs
是要匹配的附加屬性序列(在類別模式中指定為關鍵字引數),kwd_patterns
是相應的模式(在類別模式中指定為關鍵字的值)。
如果主題是指定類別的實例,所有位置模式都與相應的類別定義屬性匹配,並且任何指定的關鍵字屬性與其相應模式匹配,則此模式成功。
注意:類別可以定義一個回傳 self 的特性 (property),以便將模式節點與正在匹配的實例進行匹配。一些內建型別也以這種方式匹配,如同匹配陳述式文件中所述。
>>> print(ast.dump(ast.parse("""
... match x:
... case Point2D(0, 0):
... ...
... case Point3D(x=0, y=0, z=0):
... ...
... """), indent=4))
Module(
body=[
Match(
subject=Name(id='x', ctx=Load()),
cases=[
match_case(
pattern=MatchClass(
cls=Name(id='Point2D', ctx=Load()),
patterns=[
MatchValue(
value=Constant(value=0)),
MatchValue(
value=Constant(value=0))]),
body=[
Expr(
value=Constant(value=Ellipsis))]),
match_case(
pattern=MatchClass(
cls=Name(id='Point3D', ctx=Load()),
kwd_attrs=[
'x',
'y',
'z'],
kwd_patterns=[
MatchValue(
value=Constant(value=0)),
MatchValue(
value=Constant(value=0)),
MatchValue(
value=Constant(value=0))]),
body=[
Expr(
value=Constant(value=Ellipsis))])])])
在 3.10 版被加入.
匹配的 「as 模式 (as-pattern)」,為捕獲模式 (capture pattern) 或通配模式 (wildcard pattern)。pattern
包含主題將與之匹配的匹配模式。如果模式為 None
,則該節點代表捕獲模式(即裸名 (bare name))並且始終會成功。
name
屬性包含模式成功時將綁定的名稱。如果 name
為 None
,則 pattern
也必須為 None
,並且節點代表通配模式。
>>> print(ast.dump(ast.parse("""
... match x:
... case [x] as y:
... ...
... case _:
... ...
... """), indent=4))
Module(
body=[
Match(
subject=Name(id='x', ctx=Load()),
cases=[
match_case(
pattern=MatchAs(
pattern=MatchSequence(
patterns=[
MatchAs(name='x')]),
name='y'),
body=[
Expr(
value=Constant(value=Ellipsis))]),
match_case(
pattern=MatchAs(),
body=[
Expr(
value=Constant(value=Ellipsis))])])])
在 3.10 版被加入.
匹配的 「or 模式 (or-pattern)」。 or 模式依次將其每個子模式與主題進行匹配,直到成功為止,然後 or 模式就會被認為是成功的。如果沒有一個子模式成功,則 or 模式將失敗。 patterns
屬性包含將與主題進行匹配的匹配模式節點串列。
>>> print(ast.dump(ast.parse("""
... match x:
... case [x] | (y):
... ...
... """), indent=4))
Module(
body=[
Match(
subject=Name(id='x', ctx=Load()),
cases=[
match_case(
pattern=MatchOr(
patterns=[
MatchSequence(
patterns=[
MatchAs(name='x')]),
MatchAs(name='y')]),
body=[
Expr(
value=Constant(value=Ellipsis))])])])
在 3.10 版被加入.
A # type: ignore
comment located at lineno.
tag is the optional tag specified by the form # type: ignore <tag>
.
>>> print(ast.dump(ast.parse('x = 1 # type: ignore', type_comments=True), indent=4))
Module(
body=[
Assign(
targets=[
Name(id='x', ctx=Store())],
value=Constant(value=1))],
type_ignores=[
TypeIgnore(lineno=1, tag='')])
>>> print(ast.dump(ast.parse('x: bool = 1 # type: ignore[assignment]', type_comments=True), indent=4))
Module(
body=[
AnnAssign(
target=Name(id='x', ctx=Store()),
annotation=Name(id='bool', ctx=Load()),
value=Constant(value=1),
simple=1)],
type_ignores=[
TypeIgnore(lineno=1, tag='[assignment]')])
備註
TypeIgnore
nodes are not generated when the type_comments parameter
is set to False
(default). See ast.parse()
for more details.
在 3.8 版被加入.
型別參數可以存在於類別、函式和型別別名上。
一個 typing.TypeVar
。name
是型別變數的名稱。bound
是(如果有存在的)界限 (bound) 或約束 (constraint)。如果 bound
是一個 Tuple
,它代表約束;否則它代表界限。default_value
為預設值;如果 TypeVar
沒有預設值,那此屬性會被設為 None
。
>>> print(ast.dump(ast.parse("type Alias[T: int = bool] = list[T]"), indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Alias', ctx=Store()),
type_params=[
TypeVar(
name='T',
bound=Name(id='int', ctx=Load()),
default_value=Name(id='bool', ctx=Load()))],
value=Subscript(
value=Name(id='list', ctx=Load()),
slice=Name(id='T', ctx=Load()),
ctx=Load()))])
在 3.12 版被加入.
在 3.13 版的變更: 新增 default_value 參數。
一個 typing.ParamSpec
。name
是參數規範的名稱。default_value
是預設值;如果 ParamSpec
沒有預設值,則該屬性將設定為 None
。
>>> print(ast.dump(ast.parse("type Alias[**P = [int, str]] = Callable[P, int]"), indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Alias', ctx=Store()),
type_params=[
ParamSpec(
name='P',
default_value=List(
elts=[
Name(id='int', ctx=Load()),
Name(id='str', ctx=Load())],
ctx=Load()))],
value=Subscript(
value=Name(id='Callable', ctx=Load()),
slice=Tuple(
elts=[
Name(id='P', ctx=Load()),
Name(id='int', ctx=Load())],
ctx=Load()),
ctx=Load()))])
在 3.12 版被加入.
在 3.13 版的變更: 新增 default_value 參數。
一個 typing.TypeVarTuple
。name
是型別變數元組的名稱。default_value
為預設值;如果 TypeVarTuple
沒有預設值,那此屬性會被設為 None
。
>>> print(ast.dump(ast.parse("type Alias[*Ts = ()] = tuple[*Ts]"), indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Alias', ctx=Store()),
type_params=[
TypeVarTuple(
name='Ts',
default_value=Tuple(ctx=Load()))],
value=Subscript(
value=Name(id='tuple', ctx=Load()),
slice=Tuple(
elts=[
Starred(
value=Name(id='Ts', ctx=Load()),
ctx=Load())],
ctx=Load()),
ctx=Load()))])
在 3.12 版被加入.
在 3.13 版的變更: 新增 default_value 參數。
一個函式定義。
name
是函式名稱的原始字串。
args
是一個 arguments
節點。
body
是函式內節點的串列。
decorator_list
是要應用的裝飾器串列,在最外層者會被儲存在首位(即串列中首位將會是最後一個被應用的那個)。
returns
是回傳註釋。
type_params
是型別參數的串列。
type_comment
是一個可選字串,其中的註解為型別註釋。
在 3.12 版的變更: 新增了 type_params
。
lambda
是可以在運算式內使用的最小函式定義。與 FunctionDef
不同,body
保存單個節點。
>>> print(ast.dump(ast.parse('lambda x,y: ...'), indent=4))
Module(
body=[
Expr(
value=Lambda(
args=arguments(
args=[
arg(arg='x'),
arg(arg='y')]),
body=Constant(value=Ellipsis)))])
函式的引數。
串列中的單個引數。arg
是引數名稱的原始字串,annotation
是它的註釋,例如 Name
節點。
type_comment
是一個可選字串,其註解為型別註釋
>>> print(ast.dump(ast.parse("""\
... @decorator1
... @decorator2
... def f(a: 'annotation', b=1, c=2, *d, e, f=3, **g) -> 'return annotation':
... pass
... """), indent=4))
Module(
body=[
FunctionDef(
name='f',
args=arguments(
args=[
arg(
arg='a',
annotation=Constant(value='annotation')),
arg(arg='b'),
arg(arg='c')],
vararg=arg(arg='d'),
kwonlyargs=[
arg(arg='e'),
arg(arg='f')],
kw_defaults=[
None,
Constant(value=3)],
kwarg=arg(arg='g'),
defaults=[
Constant(value=1),
Constant(value=2)]),
body=[
Pass()],
decorator_list=[
Name(id='decorator1', ctx=Load()),
Name(id='decorator2', ctx=Load())],
returns=Constant(value='return annotation'))])
一個 return
陳述式。
>>> print(ast.dump(ast.parse('return 4'), indent=4))
Module(
body=[
Return(
value=Constant(value=4))])
一個 yield
或 yield from
運算式。因為這些是運算式,所以如果不使用發送回來的值,則必須將它們包裝在 Expr
節點中。
>>> print(ast.dump(ast.parse('yield x'), indent=4))
Module(
body=[
Expr(
value=Yield(
value=Name(id='x', ctx=Load())))])
>>> print(ast.dump(ast.parse('yield from x'), indent=4))
Module(
body=[
Expr(
value=YieldFrom(
value=Name(id='x', ctx=Load())))])
global
和 nonlocal
陳述式。names
是原始字串的串列。
>>> print(ast.dump(ast.parse('global x,y,z'), indent=4))
Module(
body=[
Global(
names=[
'x',
'y',
'z'])])
>>> print(ast.dump(ast.parse('nonlocal x,y,z'), indent=4))
Module(
body=[
Nonlocal(
names=[
'x',
'y',
'z'])])
一個類別定義。
name
是類別名稱的原始字串
bases
是被顯式指定的基底類別節點串列。
keywords
是一個 keyword
節點的串列,主要用於 'metaclass'(元類別)。如 PEP 3115 所述,其他關鍵字將被傳遞到 metaclass。
body
是表示類別定義中程式碼的節點串列。
decorator_list
是一個節點串列,如 FunctionDef
中所示。
type_params
是型別參數的串列。
>>> print(ast.dump(ast.parse("""\
... @decorator1
... @decorator2
... class Foo(base1, base2, metaclass=meta):
... pass
... """), indent=4))
Module(
body=[
ClassDef(
name='Foo',
bases=[
Name(id='base1', ctx=Load()),
Name(id='base2', ctx=Load())],
keywords=[
keyword(
arg='metaclass',
value=Name(id='meta', ctx=Load()))],
body=[
Pass()],
decorator_list=[
Name(id='decorator1', ctx=Load()),
Name(id='decorator2', ctx=Load())])])
在 3.12 版的變更: 新增了 type_params
。
一個 async def
函式定義。與 FunctionDef
具有相同的欄位。
在 3.12 版的變更: 新增了 type_params
。
一個 await
運算式。value
是它等待的東西。僅在 AsyncFunctionDef
主體 (body) 中有效。
>>> print(ast.dump(ast.parse("""\
... async def f():
... await other_func()
... """), indent=4))
Module(
body=[
AsyncFunctionDef(
name='f',
args=arguments(),
body=[
Expr(
value=Await(
value=Call(
func=Name(id='other_func', ctx=Load()))))])])
async for
迴圈和 async with
情境管理器。它們分別具有與 For
和 With
相同的欄位。僅在 AsyncFunctionDef
主體中有效。
備註
當字串被 ast.parse()
剖析時,回傳樹的運算子節點(ast.operator
、ast.unaryop
、ast.cmpop
、:class: ast.boolop
和 ast.expr_context
)將是單例。對其中之一的更改將反映在所有其他出現的相同值中(例如 ast.Add
)。
ast
輔助程式¶除了節點類別之外,ast
模組還定義了這些用於遍歷 (traverse) 抽象語法樹的實用函式和類別:
將原始碼剖析為 AST 節點,相當於 compile(source, filename, mode, flags=FLAGS_VALUE, optimize=optimize)
,其中 FLAGS_VALUE
在 optimize <= 0
時為 ast.PyCF_ONLY_AST
,否則為 ast.PyCF_OPTIMIZED_AST
。
如果給定 type_comments=True
,剖析器將被修改為檢查並回傳 PEP 484 和 PEP 526 指定的型別註釋。這相當於將 ast.PyCF_TYPE_COMMENTS
新增到傳遞給 compile()
的旗標中。這將報告錯誤型別註釋的語法錯誤。如果沒有此旗標,型別註釋將被忽略,並且所選 AST 節點上的 type_comment
欄位將始終為 None
。此外,# type: ignore
註釋的位置將作為 Module
的 type_ignores
屬性回傳(否則它始終是一個空串列)。
此外,如果 mode
是 'func_type'
,則輸入語法將會依據 PEP 484「簽名型別註解 (signature type comments)」而被修改,例如 (str, int) -> List[str]
。
將 feature_version
設定為元組 (major, minor)
將「盡可能」嘗試使用該 Python 版本的文法進行剖析。目前 major
必須等於 3
。例如,設定 feature_version=(3, 9)
將嘗試禁止剖析 match
陳述式。目前 major
必須為 3
、支援的最低版本為 (3, 7)
(這在未來的 Python 版本中可能會增加);最高的是 sys.version_info[0:2]
。「盡可能」嘗試意味著不能保證剖析(或剖析的成功)與在與 feature_version
對應的 Python 版本上運行時相同。
如果來源包含 null 字元 (\0
),則會引發 ValueError
。
警告
請注意,成功將原始碼剖析為 AST 物件並不能保證提供的原始碼是可以執行的有效 Python 程式碼,因為編譯步驟可能會引發進一步的 SyntaxError
例外。例如,原始的 return 42
為 return 陳述式生成一個有效的 AST 節點,但它不能單獨編譯(它需要位於函式節點內)。
特別是 ast.parse()
不會執行任何範圍檢查,而編譯步驟才會執行此操作。
警告
由於 Python AST 編譯器中的堆疊 (stack) 深度限制,太大或太複雜的字串可能會導致 Python 直譯器崩潰。
在 3.8 版的變更: 新增 type_comments
、mode='func_type'
與 feature_version
。
在 3.13 版的變更: feature_version
的最低支援版本現在是 (3, 7)
。新增了 optimize
引數。
反剖析 ast.AST
物件並生成一個帶有程式碼的字串,如果使用 ast.parse()
剖析回來,該程式碼將生成等效的 ast.AST
物件。
警告
生成的程式碼字串不一定等於生成 ast.AST
物件的原始程式碼(沒有任何編譯器最佳化,例如常數元組/凍結集合)。
警告
嘗試剖析高度複雜的運算式會導致 RecursionError
。
在 3.9 版被加入.
為僅包含 Python 文本或容器之顯示的運算式節點或字串來求值。提供的字串或節點只能包含以下 Python 文本結構:字串、位元組、數字、元組、串列、字典、集合、布林值、None
和 Ellipsis
。
這可用於為包含 Python 值的字串求值,而無需自己剖析這些值。它無法計算任意複雜的運算式,例如涉及運算子或索引。
該函式過去被記錄為「安全」,但沒有定義其含義,這有點誤導讀者,它是特別設計為不去執行 Python 程式碼,與更通用的 eval()
不同。沒有命名空間、沒有名稱查找、也沒有呼叫的能力。但它也不能免受攻擊:相對較小的輸入可能會導致記憶體耗盡或 C 堆疊耗盡,從而導致行程崩潰。某些輸入也可能會出現 CPU 消耗過多而導致拒絕服務的情況。因此不建議在不受信任的資料上呼叫它。
警告
由於 Python AST 編譯器的堆疊深度限制,Python 直譯器可能會崩潰。
它可能會引發 ValueError
、TypeError
、SyntaxError
、MemoryError
和 RecursionError
,具體取決於格式錯誤的輸入。
在 3.2 版的變更: 現在允許位元組和集合文本 (set literal)。
在 3.9 版的變更: 現在支援使用 'set()'
建立空集合。
在 3.10 版的變更: 對於字串輸入,前導空格和定位字元 (tab) 現在已被去除。
回傳給定 node 的文件字串 (docstring)(必須是 FunctionDef
、AsyncFunctionDef
、ClassDef
或 Module
節點)或如果它沒有文件字串則為 None
。如果 clean 為 true,則使用 inspect.cleandoc()
清理文件字串的縮排。
在 3.5 版的變更: 目前已支援 AsyncFunctionDef
。
取得生成 node 的 source 的原始碼片段。如果某些位置資訊(lineno
、end_lineno
、col_offset
或 end_col_offset
)遺漏,則回傳 None
。
如果 padded 為 True
,則多列陳述式的第一列將用空格填充 (padded) 以匹配其原始位置。
在 3.8 版被加入.
當你使用 compile()
編譯節點樹時,對於每個有支援 lineno
和 col_offset
屬性之節點,編譯器預期他們的這些屬性都要存在。填入生成的節點相當繁瑣,因此該輔助工具透過將這些屬性設定為父節點的值,在尚未設定的地方遞迴地新增這些屬性。它從 node 開始遞迴地作用。
將樹中從 node 開始的每個節點的列號和結束列號增加 n。這對於「移動程式碼」到檔案中的不同位置很有用。
如果可行,將原始位置(lineno
、col_offset
、end_lineno
和 end_col_offset
)從 old_node 複製到 new_node,並回傳 new_node 。
為 node 上存在的 node._fields
中的每個欄位生成一個 (fieldname, value)
元組。
生成 node 的所有直接子節點,即作為節點的所有欄位以及作為節點串列欄位的所有項目。
遞迴地生成樹中從 node 開始的所有後代節點(包括 node 本身),不按指定順序。如果你只想就地修改節點而不關心情境,這非常有用。
節點瀏覽者基底類別,它遍歷抽象語法樹並為找到的每個節點呼叫瀏覽者函式。該函式可能會回傳一個由 visit()
方法轉發的值。
這個類別應該被子類別化,子類別新增瀏覽者方法。
瀏覽一個節點。預設實作呼叫名為 self.visit_classname
的方法,其中 classname 是節點類別的名稱,或者在該方法不存在時呼叫 generic_visit()
。
該瀏覽者對該節點的所有子節點呼叫 visit()
。
請注意,除非瀏覽者呼叫 generic_visit()
或瀏覽它們本身,否則不會瀏覽具有自定義瀏覽者方法的節點之子節點。
處理所有常數節點。
如果你想在遍歷期間將變更應用 (apply) 於節點,請不要使用 NodeVisitor
。為此,有個允許修改的特殊遍歷瀏覽者工具 NodeTransformer
。
在 3.8 版之後被棄用: visit_Num()
、visit_Str()
、visit_Bytes()
、visit_NameConstant()
和 visit_Ellipsis()
方法現已棄用,並且不會在未來的Python 版本中被呼叫。新增 visit_Constant()
方法來處理所有常數節點。
一個 NodeVisitor
子類別,它會遍歷抽象語法樹並允許修改節點。
NodeTransformer
將遍歷 AST 並使用瀏覽者方法的回傳值來替換或刪除舊節點。如果瀏覽者方法的回傳值為 None
,則該節點將從其位置中刪除,否則將被替換為回傳值。回傳值可能是原始節點,在這種情況下不會發生替換。
下面是一個示範用的 transformer,它將查找所有出現名稱 (foo
) 並改寫為 data['foo']
:
class RewriteName(NodeTransformer):
def visit_Name(self, node):
return Subscript(
value=Name(id='data', ctx=Load()),
slice=Constant(value=node.id),
ctx=node.ctx
)
請記住,如果你正在操作的節點有子節點,你必須自己轉換子節點或先呼叫該節點的 generic_visit()
方法。
對於屬於陳述式總集 (collection) 一部分的節點(適用於所有陳述式節點),瀏覽者還可以回傳節點串列,而不僅僅是單個節點。
如果 NodeTransformer
引進了新節點(不屬於原始樹的一部分),但沒有給它們提供位置資訊(例如 lineno
),則應使用新的子樹呼叫 fix_missing_locations()
以重新計算位置資訊:
tree = ast.parse('foo', mode='eval')
new_tree = fix_missing_locations(RewriteName().visit(tree))
你通常會像這樣使用 transformer:
node = YourTransformer().visit(node)
回傳 node 中樹的格式化傾印 (formatted dump),這主要用於除錯。如果 annotate_fields 為 true(為預設值),則回傳的字串將顯示欄位的名稱和值。如果 annotate_fields 為 false,則透過省略明確的欄位名稱,結果字串將更加縮減簡潔。預設情況下,不會傾印列號和行偏移量等屬性。如果需要,可以設定 include_attributes 為 true。
如果 indent 是非負整數或字串,那麼樹將使用該縮排級別來做漂亮印出 (pretty-print)。縮排級別 0、負數或 ""
只會插入換列符號 (newlines)。None
(預設值)代表選擇單列表示。使用正整數縮排可以在每個級別縮排相同數量的空格。如果 indent 是一個字串(例如 "\t"
),則該字串用於縮排每個級別。
如果 show_empty 為 False
(預設值),則輸出中將省略 False
的空串列和欄位。
在 3.9 版的變更: 新增 indent 選項。
在 3.13 版的變更: 新增 show_empty 選項。
>>> print(ast.dump(ast.parse("""\
... async def f():
... await other_func()
... """), indent=4, show_empty=True))
Module(
body=[
AsyncFunctionDef(
name='f',
args=arguments(
posonlyargs=[],
args=[],
kwonlyargs=[],
kw_defaults=[],
defaults=[]),
body=[
Expr(
value=Await(
value=Call(
func=Name(id='other_func', ctx=Load()),
args=[],
keywords=[])))],
decorator_list=[],
type_params=[])],
type_ignores=[])
可以將以下旗標傳遞給 compile()
以變更對程式的編譯效果:
啟用對最高階 await
、async for
、async with
和非同步綜合運算的支援。
在 3.8 版被加入.
生成並回傳抽象語法樹,而不是回傳已編譯的程式碼物件。
回傳的 AST 會根據 compile()
或 ast.parse()
中的 optimize 引數進行最佳化。
在 3.13 版被加入.
在 3.9 版被加入.
ast
模組可以作為腳本從命令列執行,可以像這樣簡單地做到:
python -m ast [-m <mode>] [-a] [infile]
以下選項可被接受:
顯示幫助訊息並退出。
不要剖析型別註解。
包括列號和行偏移量等屬性。
如果指定了 infile
,則其內容將被剖析為 AST 並傾印 (dump) 到 stdout。否則會從 stdin 讀取內容。
也參考
Green Tree Snakes 是一個外部文件資源,提供了有關使用 Python AST 的詳細資訊。
ASTTokens 使用生成它們的原始碼中的標記和文本的位置來註釋 Python AST。這對於進行原始碼轉換的工具很有幫助。
leoAst.py 透過在 token 和 ast 節點之間插入雙向鏈結,統一了 python 程式的基於 token 和基於剖析樹的視圖。
LibCST 將程式碼剖析為具體語法樹 (Concrete Syntax Tree),看起來像 ast 樹並保留所有格式詳細資訊。它對於建置自動重構 (codemod) 應用程式和 linter 非常有用。
Parso 是一個 Python 剖析器,支援不同 Python 版本的錯誤復原和往返剖析。Parso 還能夠列出 Python 檔案中的多個語法錯誤。