ast —抽象構文木
ソースコード: :source: `Lib / ast.py`
ast モジュールは、PythonアプリケーションがPython抽象構文文法のツリーを処理するのに役立ちます。 抽象構文自体は、Pythonのリリースごとに変わる可能性があります。 このモジュールは、現在の文法がどのように見えるかをプログラムで見つけるのに役立ちます。
抽象構文木は、ast.PyCF_ONLY_AST
をフラグとして compile()組み込み関数に渡すか、これで提供される parse()ヘルパーを使用して生成できます。モジュール。 結果は、クラスがすべて ast.AST から継承するオブジェクトのツリーになります。 組み込みの compile()関数を使用して、抽象構文ツリーをPythonコードオブジェクトにコンパイルできます。
ノードクラス
- class ast.AST
これは、すべてのASTノードクラスのベースです。 実際のノードクラスは、
Parser/Python.asdl
ファイルから派生しています。このファイルは以下に再現されています。 それらは_ast
Cモジュールで定義され、 ast で再エクスポートされます。抽象文法の左側の記号ごとに1つのクラスが定義されています(たとえば、
ast.stmt
またはast.expr
)。 さらに、右側のコンストラクターごとに1つのクラスが定義されています。 これらのクラスは、左側のツリーのクラスを継承します。 たとえば、ast.BinOp
はast.expr
から継承します。 代替(別名「合計」)のあるプロダクションルールの場合、左側のクラスは抽象的です。特定のコンストラクターノードのインスタンスのみが作成されます。- _fields
各具象クラスには、すべての子ノードの名前を与える属性 _fields があります。
具象クラスの各インスタンスには、文法で定義されているタイプの子ノードごとに1つの属性があります。 たとえば、
ast.BinOp
インスタンスには、タイプast.expr
の属性left
があります。これらの属性が文法でオプションとしてマークされている場合(疑問符を使用)、値は
None
である可能性があります。 属性が0個以上の値(アスタリスクでマークされている)を持つことができる場合、値はPythonリストとして表されます。 compile()を使用してASTをコンパイルするときは、すべての可能な属性が存在し、有効な値を持っている必要があります。
- lineno
col_offset
end_lineno
end_col_offset ast.expr
およびast.stmt
サブクラスのインスタンスには、 lineno 、 col_offset 、 lineno 、および col_offset 属性があります。 。 lineno と end_lineno は、ソーステキストスパンの最初と最後の行番号(1-インデックスが付けられているため、最初の行は1行目です)と col_offset と[ X172X] end_col_offset は、ノードを生成した最初と最後のトークンの対応するUTF-8バイトオフセットです。 パーサーはUTF-8を内部で使用するため、UTF-8オフセットが記録されます。終了位置はコンパイラーによって必須ではないため、オプションであることに注意してください。 終了オフセットは、最後のシンボルの後です。たとえば、
source_line[node.col_offset : node.end_col_offset]
を使用して1行の式ノードのソースセグメントを取得できます。
クラス
ast.T
のコンストラクターは、その引数を次のように解析します。位置引数がある場合は、
T._fields
の項目と同じ数でなければなりません。 これらの名前の属性として割り当てられます。キーワード引数がある場合、それらは同じ名前の属性を指定された値に設定します。
たとえば、
ast.UnaryOp
ノードを作成してデータを入力するには、次のように使用できます。node = ast.UnaryOp() node.op = ast.USub() node.operand = ast.Constant() node.operand.value = 5 node.operand.lineno = 0 node.operand.col_offset = 0 node.lineno = 0 node.col_offset = 0
またはよりコンパクト
node = ast.UnaryOp(ast.USub(), ast.Constant(5, lineno=0, col_offset=0), lineno=0, col_offset=0)
バージョン3.8で変更:クラスast.Constant
がすべての定数に使用されるようになりました。
バージョン3.8以降非推奨:古いクラスast.Num
、ast.Str
、ast.Bytes
、ast.NameConstant
、ast.Ellipsis
は引き続き利用可能、ただし、将来のPythonリリースで削除される予定です。 その間、それらをインスタンス化すると、別のクラスのインスタンスが返されます。
抽象文法
抽象文法は現在、次のように定義されています。
-- ASDL's 5 builtin types are:
-- identifier, int, string, object, constant
module Python
{
mod = Module(stmt* body, type_ignore *type_ignores)
| Interactive(stmt* body)
| Expression(expr body)
| FunctionType(expr* argtypes, expr returns)
-- not really an actual node but useful in Jython's typesystem.
| Suite(stmt* body)
stmt = FunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list, expr? returns,
string? type_comment)
| AsyncFunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list, expr? returns,
string? type_comment)
| ClassDef(identifier name,
expr* bases,
keyword* keywords,
stmt* body,
expr* decorator_list)
| Return(expr? value)
| Delete(expr* targets)
| Assign(expr* targets, expr value, string? type_comment)
| 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)
| Raise(expr? exc, expr? cause)
| Try(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
-- XXX Jython will be different
-- 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, slice 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)
-- 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 | AugLoad | AugStore | Param
slice = Slice(expr? lower, expr? upper, expr? step)
| ExtSlice(slice* dims)
| Index(expr value)
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)
-- import name with optional 'as' alias.
alias = (identifier name, identifier? asname)
withitem = (expr context_expr, expr? optional_vars)
type_ignore = TypeIgnore(int lineno, string tag)
}
ast ヘルパー
ノードクラスとは別に、 ast モジュールは、抽象構文木をトラバースするためのこれらのユーティリティ関数とクラスを定義します。
- ast.parse(source, filename='<unknown>', mode='exec', *, type_comments=False, feature_version=None)
ソースをASTノードに解析します。
compile(source, filename, mode, ast.PyCF_ONLY_AST)
と同等です。type_comments=True
が指定されている場合、パーサーは、 PEP 484 および PEP 526 [で指定されたタイプコメントをチェックして返すように変更されます。 X146X]。 これは、 compile()に渡されるフラグにast.PyCF_TYPE_COMMENTS
を追加することと同じです。 これにより、タイプコメントの置き忘れの構文エラーが報告されます。 このフラグがないと、タイプコメントは無視され、選択したASTノードのtype_comment
フィールドは常にNone
になります。 さらに、# type: ignore
コメントの場所は、Module
のtype_ignores
属性として返されます(それ以外の場合は、常に空のリストです)。さらに、
mode
が'func_type'
の場合、入力構文は PEP 484 の「署名タイプのコメント」に対応するように変更されます。(str, int) -> List[str]
。また、
feature_version
をタプル(major, minor)
に設定すると、そのPythonバージョンの文法を使用して解析が試行されます。 現在、major
は3
と等しくなければなりません。 たとえば、feature_version=(3, 4)
を設定すると、変数名としてasync
とawait
を使用できるようになります。 サポートされている最低バージョンは(3, 4)
です。 最高はsys.version_info[0:2]
です。警告
PythonのASTコンパイラではスタックの深さが制限されているため、十分に大きい/複雑な文字列でPythonインタプリタがクラッシュする可能性があります。
バージョン3.8で変更:
type_comments
、mode='func_type'
、feature_version
を追加。
- ast.literal_eval(node_or_string)
Pythonリテラルまたはコンテナ表示を含む式ノードまたは文字列を安全に評価します。 提供される文字列またはノードは、次のPythonリテラル構造のみで構成されます:文字列、バイト、数値、タプル、リスト、dict、セット、ブール値、および
None
。これは、信頼できないソースからのPython値を含む文字列を、値を自分で解析することなく安全に評価するために使用できます。 演算子やインデックス付けなど、任意の複雑な式を評価することはできません。
警告
PythonのASTコンパイラではスタックの深さが制限されているため、十分に大きい/複雑な文字列でPythonインタプリタがクラッシュする可能性があります。
バージョン3.2で変更:バイトとセットリテラルを許可するようになりました。
- ast.get_docstring(node, clean=True)
指定されたノード(
FunctionDef
、AsyncFunctionDef
、ClassDef
、またはModule
ノードである必要があります)のdocstringを返します。None
docstringがない場合。 clean がtrueの場合、 inspect.cleandoc()を使用してdocstringのインデントをクリーンアップします。バージョン3.5で変更:
AsyncFunctionDef
がサポートされるようになりました。
- ast.get_source_segment(source, node, *, padded=False)
ノードを生成したソースのソースコードセグメントを取得します。 一部の位置情報(
lineno
、end_lineno
、col_offset
、またはend_col_offset
)が欠落している場合は、None
を返します。padded が
True
の場合、複数行のステートメントの最初の行には、元の位置に一致するスペースが埋め込まれます。バージョン3.8の新機能。
- ast.fix_missing_locations(node)
- compile()を使用してノードツリーをコンパイルすると、コンパイラは、それらをサポートするすべてのノードに
lineno
およびcol_offset
属性を期待します。 これは、生成されたノードに入力するのがかなり面倒なので、このヘルパーは、これらの属性を親ノードの値に設定することにより、まだ設定されていない場所に再帰的に追加します。 ノードから再帰的に動作します。
- 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._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()を呼び出すか、それ自体にアクセスしない限り、アクセスされないことに注意してください。
トラバーサル中にノードに変更を適用する場合は、 NodeVisitor を使用しないでください。 このために、変更を許可する特別な訪問者( NodeTransformer )が存在します。
バージョン3.8以降非推奨:メソッド
visit_Num()
、visit_Str()
、visit_Bytes()
、visit_NameConstant()
、visit_Ellipsis()
は非推奨になり、今後のPythonバージョンでは呼び出されません。visit_Constant()
メソッドを追加して、すべての定数ノードを処理します。
- class ast.NodeTransformer
NodeVisitor サブクラスは、抽象構文ツリーをウォークし、ノードの変更を可能にします。
NodeTransformer はASTをウォークし、ビジターメソッドの戻り値を使用して古いノードを置き換えるか削除します。 ビジターメソッドの戻り値が
None
の場合、ノードはその場所から削除されます。それ以外の場合は、戻り値に置き換えられます。 戻り値は元のノードである可能性があり、その場合、置換は行われません。これは、名前ルックアップ(
foo
)のすべてのオカレンスをdata['foo']
に書き換えるトランスフォーマーの例です。class RewriteName(NodeTransformer): def visit_Name(self, node): return Subscript( value=Name(id='data', ctx=Load()), slice=Index(value=Constant(value=node.id)), ctx=node.ctx )
操作しているノードに子ノードがある場合は、子ノードを自分で変換するか、最初にノードの
generic_visit()
メソッドを呼び出す必要があることに注意してください。ステートメントのコレクションの一部であったノード(すべてのステートメントノードに適用される)の場合、訪問者は単一のノードだけでなく、ノードのリストを返すこともあります。
NodeTransformer が場所情報(
lineno
など)を提供せずに新しいノード(元のツリーの一部ではなかった)を導入する場合、 fix_missing_locations()を次のように呼び出す必要があります。位置情報を再計算するための新しいサブツリー:tree = ast.parse('foo', mode='eval') new_tree = fix_missing_locations(RewriteName().visit(tree))
通常、次のようなトランスフォーマーを使用します。
node = YourTransformer().visit(node)
- ast.dump(node, annotate_fields=True, include_attributes=False)
- ノードにあるツリーのフォーマットされたダンプを返します。 これは主にデバッグの目的で役立ちます。 annotate_fields がtrue(デフォルト)の場合、返される文字列にはフィールドの名前と値が表示されます。 annotate_fields がfalseの場合、明確なフィールド名を省略することで、結果の文字列がよりコンパクトになります。 行番号や列オフセットなどの属性は、デフォルトではダンプされません。 これが必要な場合は、 include_attributes をtrueに設定できます。
も参照してください
Green Tree Snakes 、外部ドキュメントリソースには、PythonASTの操作に関する詳細が記載されています。
ASTTokens は、Python ASTに、それらを生成したソースコード内のトークンとテキストの位置で注釈を付けます。 これは、ソースコードを変換するツールに役立ちます。
leoAst.py は、トークンとastノードの間に双方向リンクを挿入することにより、Pythonプログラムのトークンベースのビューと解析ツリーベースのビューを統合します。
LibCST は、コードをastツリーのように見え、すべてのフォーマットの詳細を保持する具体的な構文ツリーとして解析します。 自動リファクタリング(codemod)アプリケーションやリンターの構築に役立ちます。
Parso は、さまざまなPythonバージョン(複数のPythonバージョン)のエラー回復とラウンドトリップ解析をサポートするPythonパーサーです。 Parsoは、Pythonファイル内の複数の構文エラーを一覧表示することもできます。