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 ast.expr
およびast.stmt
サブクラスのインスタンスには、 lineno および col_offset 属性があります。 lineno はソーステキストの行番号(1-インデックスが付けられているため、最初の行は1行目)であり、 col_offset は、ノード。 パーサーはUTF-8を内部で使用するため、UTF-8オフセットが記録されます。
クラス
ast.T
のコンストラクターは、その引数を次のように解析します。位置引数がある場合は、
T._fields
の項目と同じ数でなければなりません。 これらの名前の属性として割り当てられます。キーワード引数がある場合、それらは同じ名前の属性を指定された値に設定します。
たとえば、
ast.UnaryOp
ノードを作成してデータを入力するには、次のように使用できます。node = ast.UnaryOp() node.op = ast.USub() node.operand = ast.Num() node.operand.n = 5 node.operand.lineno = 0 node.operand.col_offset = 0 node.lineno = 0 node.col_offset = 0
またはよりコンパクト
node = ast.UnaryOp(ast.USub(), ast.Num(5, lineno=0, col_offset=0), lineno=0, col_offset=0)
抽象文法
抽象文法は現在、次のように定義されています。
-- ASDL's 7 builtin types are:
-- identifier, int, string, bytes, object, singleton, constant
--
-- singleton: None, True or False
-- constant can be None, whereas None means "no value" for object.
module Python
{
mod = Module(stmt* body)
| Interactive(stmt* body)
| Expression(expr body)
-- 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)
| AsyncFunctionDef(identifier name, arguments args,
stmt* body, expr* decorator_list, expr? returns)
| ClassDef(identifier name,
expr* bases,
keyword* keywords,
stmt* body,
expr* decorator_list)
| Return(expr? value)
| Delete(expr* targets)
| Assign(expr* targets, 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)
| AsyncFor(expr target, expr iter, stmt* body, stmt* orelse)
| While(expr test, stmt* body, stmt* orelse)
| If(expr test, stmt* body, stmt* orelse)
| With(withitem* items, stmt* body)
| AsyncWith(withitem* items, stmt* body)
| 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)
-- BoolOp() can use left & right?
expr = BoolOp(boolop op, expr* values)
| 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)
| Num(object n) -- a number as a PyObject.
| Str(string s) -- need to specify raw, unicode, etc?
| FormattedValue(expr value, int? conversion, expr? format_spec)
| JoinedStr(expr* values)
| Bytes(bytes s)
| NameConstant(singleton value)
| Ellipsis
| Constant(constant value)
-- 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)
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)
arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults,
arg? kwarg, expr* defaults)
arg = (identifier arg, expr? annotation)
attributes (int lineno, int 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)
}
ast ヘルパー
ノードクラスとは別に、 ast モジュールは、抽象構文木をトラバースするためのこれらのユーティリティ関数とクラスを定義します。
- ast.parse(source, filename='<unknown>', mode='exec')
ソースをASTノードに解析します。
compile(source, filename, mode, ast.PyCF_ONLY_AST)
と同等です。警告
PythonのASTコンパイラではスタックの深さが制限されているため、十分に大きい/複雑な文字列でPythonインタプリタがクラッシュする可能性があります。
- 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.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
)を 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 )が存在します。
- 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=Str(s=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に設定できます。