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)
| 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)
}
節點 (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.14 版的變更: The __repr__()
output of AST
nodes includes
the values of the node fields.
在 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 專案和所有貢獻者那裡改編而來的。
根節點¶
- 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
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 版被加入.
文本 (Literals)¶
- class ast.Constant(value)¶
一個常數值。
Constant
文本的value
屬性包含它所代表的 Python 物件。表示的值可以是簡單型別,例如數字、字串或None
,但如果它們的所有元素都是常數,也可以是不可變的 (immutable) 容器型別(元組和凍結集合 (frozensets))。>>> print(ast.dump(ast.parse('123', mode='eval'), indent=4)) Expression( body=Constant(value=123))
- class ast.FormattedValue(value, conversion, format_spec)¶
表示 f 字串 (f-string) 中的單個格式化欄位的節點。如果字串包含單個格式欄位並且沒有其他內容,則可以隔離 (isolate) 該節點,否則它將出現在
JoinedStr
中。value
為任何運算式節點(例如文字、變數或函式呼叫)。conversion
是一個整數:-1: 無格式化
115:
!s
字串格式化114:
!r
重複格式化化97:
!a
ascii 格式化
format_spec
是一個JoinedStr
節點,表示值的格式,若未指定格式則為None
。conversion
和format_spec
可以同時設定。
- class ast.JoinedStr(values)¶
一個 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')]))]))
- class ast.List(elts, ctx)¶
- class ast.Tuple(elts, ctx)¶
串列或元組。
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()))
- class ast.Set(elts)¶
一個集合。
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)]))
- class ast.Dict(keys, values)¶
一個字典 (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())]))
變數¶
- class ast.Name(id, ctx)¶
一個變數名稱。
id
將名稱以字串形式保存,且ctx
是以下型別之一。
- class ast.Load¶
- class ast.Store¶
- class ast.Del¶
變數參照可用於載入變數的值、為其分配新值或刪除它。變數參照被賦予情境 (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())])])
- class ast.Starred(value, ctx)¶
一個
*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()))])
運算式¶
- class ast.Expr(value)¶
當運算式(例如函式呼叫)本身作為陳述式出現且未使用或儲存其回傳值時,它將被包裝在此容器中。
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())))])
- class ast.UnaryOp(op, operand)¶
一元運算 (unary operation)。
op
是運算子,operand
是任何運算式節點。
- class ast.UAdd¶
- class ast.USub¶
- class ast.Not¶
- class ast.Invert¶
一元運算子標記。
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())))
- class ast.BinOp(left, op, right)¶
二元運算 (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())))
- class ast.Add¶
- class ast.Sub¶
- class ast.Mult¶
- class ast.Div¶
- class ast.FloorDiv¶
- class ast.Mod¶
- class ast.Pow¶
- class ast.LShift¶
- class ast.RShift¶
- class ast.BitOr¶
- class ast.BitXor¶
- class ast.BitAnd¶
- class ast.MatMult¶
二元運算子 token。
- class ast.BoolOp(op, values)¶
布林運算 '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())]))
- class ast.Compare(left, ops, comparators)¶
兩個或多個值的比較。
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)]))
- class ast.Eq¶
- class ast.NotEq¶
- class ast.Lt¶
- class ast.LtE¶
- class ast.Gt¶
- class ast.GtE¶
- class ast.Is¶
- class ast.IsNot¶
- class ast.In¶
- class ast.NotIn¶
比較運算子 token。
- class ast.Call(func, args, keywords)¶
一個函式呼叫。
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()))]))
- class ast.keyword(arg, value)¶
函式呼叫或類別定義的關鍵字引數。
arg
是參數名稱的原始字串,value
是要傳入的節點。
- class ast.IfExp(test, body, orelse)¶
像是
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())))
- class ast.Attribute(value, attr, ctx)¶
屬性的存取,例如
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()))
- class ast.NamedExpr(target, value)¶
一個附名運算式 (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 版被加入.
下標 (Subscripting)¶
- class ast.Subscript(value, slice, ctx)¶
一個下標,例如
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()))
- class ast.Slice(lower, upper, step)¶
常規切片(形式為
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()))
綜合運算式 (comprehensions)¶
- class ast.ListComp(elt, generators)¶
- class ast.SetComp(elt, generators)¶
- class ast.GeneratorExp(elt, generators)¶
- class ast.DictComp(key, value, generators)¶
串列和集合綜合運算、生成器運算式和字典綜合運算。
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)]))
- class ast.comprehension(target, iter, ifs, is_async)¶
綜合運算中的一個
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)]))
陳述式¶
- class ast.Assign(targets, value, type_comment)¶
一個賦值。
targets
是節點串列,value
是單個節點。targets
中的多個節點表示為每個節點分配相同的值。解包是透過在targets
中放置一個Tuple
或List
來表示的。- type_comment¶
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()))])
- class ast.AnnAssign(target, annotation, value, simple)¶
帶有型別註釋的賦值。
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)])
- class ast.AugAssign(target, op, value)¶
增加賦值 (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))])
- class ast.Raise(exc, cause)¶
一個
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()))])
- class ast.Assert(test, msg)¶
一個斷言 (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()))])
- class ast.Delete(targets)¶
代表一個
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())])])
- class ast.Pass¶
一個
pass
陳述式。>>> print(ast.dump(ast.parse('pass'), indent=4)) Module( body=[ Pass()])
- class ast.TypeAlias(name, type_params, value)¶
透過
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 版被加入.
其他僅適用於函式或迴圈內部的陳述式將在其他部分中描述。
引入 (imports)¶
- class ast.Import(names)¶
一個 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')])])
- class ast.ImportFrom(module, names, level)¶
代表
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)])
- class ast.alias(name, asname)¶
這兩個參數都是名稱的原始字串。如果要使用常規名稱,
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
之類的可選子句如果不存在,則將被儲存為空串列。
- class ast.If(test, body, orelse)¶
一個
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))])])])
- class ast.For(target, iter, body, orelse, type_comment)¶
一個
for
迴圈。target
保存迴圈賦予的變數,為單個Name
、Tuple
、List
、Attribute
或Subscript
節點。iter
保存要迴圈跑過的項目,也為單個節點。body
和orelse
包含要執行的節點串列。如果迴圈正常完成,則執行orelse
中的內容,而不是透過break
陳述式執行。- type_comment¶
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))])])
- class ast.While(test, body, orelse)¶
一個
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))])])
- class ast.Break¶
- class ast.Continue¶
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()])])])
- class ast.Try(body, handlers, orelse, finalbody)¶
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))])])
- class ast.TryStar(body, handlers, orelse, finalbody)¶
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 版被加入.
- class ast.ExceptHandler(type, name, body)¶
單個
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()])])])
- class ast.With(items, body, type_comment)¶
一個
with
區塊。items
是表示情境管理器的withitem
節點串列,body
是情境內的縮進區塊。- type_comment¶
type_comment
是一個可選字串,其中的註解為型別註釋。
- class ast.withitem(context_expr, optional_vars)¶
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())]))])])
模式匹配 (pattern matching)¶
- class ast.Match(subject, cases)¶
一個
match
陳述式。subject
保存匹配的主題(與案例匹配的物件),cases
包含具有不同案例的match_case
節點的可疊代物件。在 3.10 版被加入.
- class ast.match_case(pattern, guard, body)¶
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 版被加入.
- class ast.MatchValue(value)¶
以相等性進行比較的匹配文本或值的模式。
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 版被加入.
- class ast.MatchSingleton(value)¶
按識別性 (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 版被加入.
- class ast.MatchSequence(patterns)¶
匹配序列模式。如果主題是一個序列,
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 版被加入.
- class ast.MatchStar(name)¶
以可變長度匹配序列模式匹配序列的其餘部分。如果
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 版被加入.
- class ast.MatchMapping(keys, patterns, rest)¶
匹配對映模式。
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 版被加入.
- class ast.MatchClass(cls, patterns, kwd_attrs, kwd_patterns)¶
匹配類別模式。
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 版被加入.
- class ast.MatchAs(pattern, name)¶
匹配的 「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 版被加入.
- class ast.MatchOr(patterns)¶
匹配的 「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 版被加入.
型別參數 (type parameters)¶
型別參數可以存在於類別、函式和型別別名上。
- class ast.TypeVar(name, bound, default_value)¶
一個
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 參數。
- class ast.ParamSpec(name, 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 參數。
- class ast.TypeVarTuple(name, 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 參數。
函式和類別定義¶
- class ast.FunctionDef(name, args, body, decorator_list, returns, type_comment, type_params)¶
一個函式定義。
name
是函式名稱的原始字串。args
是一個arguments
節點。body
是函式內節點的串列。decorator_list
是要應用的裝飾器串列,在最外層者會被儲存在首位(即串列中首位將會是最後一個被應用的那個)。returns
是回傳註釋。type_params
是型別參數的串列。
- type_comment¶
type_comment
是一個可選字串,其中的註解為型別註釋。
在 3.12 版的變更: 新增了
type_params
。
- class ast.Lambda(args, body)¶
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)))])
- class ast.arguments(posonlyargs, args, vararg, kwonlyargs, kw_defaults, kwarg, defaults)¶
函式的引數。
- class ast.arg(arg, annotation, type_comment)¶
串列中的單個引數。
arg
是引數名稱的原始字串,annotation
是它的註釋,例如Name
節點。- type_comment¶
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'))])
- class ast.Return(value)¶
一個
return
陳述式。>>> print(ast.dump(ast.parse('return 4'), indent=4)) Module( body=[ Return( value=Constant(value=4))])
- class ast.Yield(value)¶
- class ast.YieldFrom(value)¶
一個
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())))])
- class ast.Global(names)¶
- class ast.Nonlocal(names)¶
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'])])
- class ast.ClassDef(name, bases, keywords, body, decorator_list, type_params)¶
一個類別定義。
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 和 await¶
- class ast.AsyncFunctionDef(name, args, body, decorator_list, returns, type_comment, type_params)¶
一個
async def
函式定義。與FunctionDef
具有相同的欄位。在 3.12 版的變更: 新增了
type_params
。
- class ast.Await(value)¶
一個
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()))))])])
- class ast.AsyncFor(target, iter, body, orelse, type_comment)¶
- class ast.AsyncWith(items, body, type_comment)¶
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.parse(source, filename='<unknown>', mode='exec', *, type_comments=False, feature_version=None, optimize=-1)¶
將原始碼剖析為 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.unparse(ast_obj)¶
反剖析
ast.AST
物件並生成一個帶有程式碼的字串,如果使用ast.parse()
剖析回來,該程式碼將生成等效的ast.AST
物件。警告
生成的程式碼字串不一定等於生成
ast.AST
物件的原始程式碼(沒有任何編譯器最佳化,例如常數元組/凍結集合)。警告
嘗試剖析高度複雜的運算式會導致
RecursionError
。在 3.9 版被加入.
- ast.literal_eval(node_or_string)¶
為僅包含 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) 現在已被去除。
- ast.get_docstring(node, clean=True)¶
回傳給定 node 的文件字串 (docstring)(必須是
FunctionDef
、AsyncFunctionDef
、ClassDef
或Module
節點)或如果它沒有文件字串則為None
。如果 clean 為 true,則使用inspect.cleandoc()
清理文件字串的縮排。在 3.5 版的變更: 目前已支援
AsyncFunctionDef
。
- ast.get_source_segment(source, node, *, padded=False)¶
獲取生成 node 的 source 的原始碼片段。如果某些位置資訊(
lineno
、end_lineno
、col_offset
或end_col_offset
)遺漏,則回傳None
。如果 padded 為
True
,則多列陳述式的第一列將用空格填充 (padded) 以匹配其原始位置。在 3.8 版被加入.
- ast.fix_missing_locations(node)¶
當你使用
compile()
編譯節點樹時,對於每個有支援lineno
和col_offset
屬性之節點,編譯器預期他們的這些屬性都要存在。填入生成的節點相當繁瑣,因此該輔助工具透過將這些屬性設定為父節點的值,在尚未設定的地方遞迴地新增這些屬性。它從 node 開始遞迴地作用。
- ast.increment_lineno(node, n=1)¶
將樹中從 node 開始的每個節點的列號和結束列號增加 n。這對於「移動程式碼」到檔案中的不同位置很有用。
- ast.copy_location(new_node, old_node)¶
如果可行,將原始位置(
lineno
、col_offset
、end_lineno
和end_col_offset
)從 old_node 複製到 new_node,並回傳 new_node 。
- ast.iter_fields(node)¶
為 node 上存在的
node._fields
中的每個欄位生成一個(fieldname, value)
元組。
- ast.iter_child_nodes(node)¶
生成 node 的所有直接子節點,即作為節點的所有欄位以及作為節點串列欄位的所有項目。
- ast.walk(node)¶
遞迴地生成樹中從 node 開始的所有後代節點(包括 node 本身),不按指定順序。如果你只想就地修改節點而不關心情境,這非常有用。
- class ast.NodeVisitor¶
節點訪問者基底類別,它遍歷抽象語法樹並為找到的每個節點呼叫訪問者函式。該函式可能會回傳一個由
visit()
方法轉發的值。這個類別應該被子類別化,子類別新增訪問者方法。
- visit(node)¶
訪問一個節點。預設實作呼叫名為
self.visit_classname
的方法,其中 classname 是節點類別的名稱,或者在該方法不存在時呼叫generic_visit()
。
- generic_visit(node)¶
該訪問者對該節點的所有子節點呼叫
visit()
。請注意,除非訪問者呼叫
generic_visit()
或訪問它們本身,否則不會訪問具有自定義訪問者方法的節點之子節點。
- visit_Constant(node)¶
處理所有常數節點。
如果你想在遍歷期間將變更應用 (apply) 於節點,請不要使用
NodeVisitor
。為此,有個允許修改的特殊遍歷訪問者工具NodeTransformer
。在 3.8 版之後被棄用:
visit_Num()
、visit_Str()
、visit_Bytes()
、visit_NameConstant()
和visit_Ellipsis()
方法現已棄用,並且不會在未來的Python 版本中被呼叫。新增visit_Constant()
方法來處理所有常數節點。
- class ast.NodeTransformer¶
一個
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)
- ast.dump(node, annotate_fields=True, include_attributes=False, *, indent=None, show_empty=False)¶
回傳 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()
以變更對程式的編譯效果:
- ast.PyCF_ALLOW_TOP_LEVEL_AWAIT¶
啟用對最高階
await
、async for
、async with
和非同步綜合運算的支援。在 3.8 版被加入.
- ast.PyCF_ONLY_AST¶
生成並回傳抽象語法樹,而不是回傳已編譯的程式碼物件。
- ast.PyCF_OPTIMIZED_AST¶
回傳的 AST 會根據
compile()
或ast.parse()
中的 optimize 引數進行最佳化。在 3.13 版被加入.
- ast.PyCF_TYPE_COMMENTS¶
啟用對 PEP 484 和 PEP 526 樣式型別註釋的支援 (
# type: <type>
,# type: ignore <stuff>
)。在 3.8 版被加入.
- ast.compare(a, b, /, *, compare_attributes=False)¶
Recursively compares two ASTs.
compare_attributes affects whether AST attributes are considered in the comparison. If compare_attributes is
False
(default), then attributes are ignored. Otherwise they must all be equal. This option is useful to check whether the ASTs are structurally equal but differ in whitespace or similar details. Attributes include line numbers and column offsets.在 3.14 版被加入.
命令列用法¶
在 3.9 版被加入.
ast
模組可以作為腳本從命令列執行,可以像這樣簡單地做到:
python -m ast [-m <mode>] [-a] [infile]
以下選項可被接受:
- -h, --help¶
顯示幫助訊息並退出。
- --no-type-comments¶
不要剖析型別註解。
- -a, --include-attributes¶
包括列號和行偏移量等屬性。
如果指定了 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 檔案中的多個語法錯誤。