Matt Layman

プログラミングについて少し「メタ」を手に入れましょう。

Pythonプログラム(インタプリタとして知っている方が良い)は、コードの実行方法をどのように「知っている」のですか?プログラミングに慣れていない場合は、次のように見えるかもしれませんmagic.In 事実、それはまだ十年以上のプロであることの後に私には魔法のように思えます。Pythonインタプリタは魔法ではありません(失望させて申し訳ありません)。codeinto命令をマシンが実行できるように変換するための予測可能な一連のステップに従かなり高いレベルでは、コードに何が起こるかは次のとおりです。

  1. コードは、通常トークンと呼ばれる部分のリストに解析されます(つまり、分割されます)。これらのトークンは、一連のルールに基づいています異なる方法で処理する必要があるもののために。たとえば、キーワードif42のような数値とは異なるトークンです。
  2. トークンの生のリストは変換されます抽象構文ツリー ASTを構築するために、この記事で詳しく説明します。ASTは、Python言語の文法に基づいて一緒にリンクされているノードのコレクションです。それが意味をなさなかったら心配してはいけないnowsince私達はそれのより多くのライトを瞬間的に照る。
  3. 抽象構文ツリーから、インタプリタはより低いレベルのformof命令と呼ばれるバイトコードを生成することができます。これらの命令はBINARY_ADDようなものであり、コンピュータがそれらを実行できるように非常に汎用的であることを意図して
  4. 利用可能なバイトコード命令を使用すると、インタプリタは最終的にコードを実行できます。バイトコードは、オペレーティングシステムの関数を呼び出すために使用され、最終的にはCPUと対話し、プログラムを実行するメモリと対話します。

さらに多くの詳細がその説明に収まる可能性がありますが、それはタイプされた文字がコンピュータのCpuによってどのように実行されるかの

ASTs as analysis tools

ソースコードがバイトコードに変換されるまでには、あなたが書いたことについて多くの理解を得るには遅すぎます。バイトコードは非常に原始的であり、インタプリタを作ることに非常に調整されていますfast.In 言い換えれば、バイトコードは、人々の上にコンピュータのために設計されています。一方、抽象構文木は、コードについての学習に役立つように、十分な構造化された情報を持っています。ASTはまだあまり人に優しいものではありませんが、バイトコード表現よりも賢明です。Pythonは「電池が含まれている」言語であるため、Astを使用するために必要なツールは標準ライブラリに組み込まれています。Astを操作するための主なツールはastモジュールです。これがどのように機能するかを見るための例を見てみましょう。

ast by example

以下は、使用するPythonスクリプトの例です。このスクリプトは、”どのモジュールがインポートされましたか?”

import astfrom pprint import pprint

def main():with open("ast_example.py", "r") as source:tree = ast.parse(source.read())

analyzer <span style="color:#f92672">=</span> Analyzer()analyzer<span style="color:#f92672">.</span>visit(tree)analyzer<span style="color:#f92672">.</span>report()

class Analyzer(ast.NodeVisitor):def init(self):self.stats = {“import”: , “from”: }

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">visit_Import</span>(self, node): <span style="color:#66d9ef">for</span> alias <span style="color:#f92672">in</span> node<span style="color:#f92672">.</span>names: self<span style="color:#f92672">.</span>stats<span style="color:#f92672">.</span>append(alias<span style="color:#f92672">.</span>name) self<span style="color:#f92672">.</span>generic_visit(node)<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">visit_ImportFrom</span>(self, node): <span style="color:#66d9ef">for</span> alias <span style="color:#f92672">in</span> node<span style="color:#f92672">.</span>names: self<span style="color:#f92672">.</span>stats<span style="color:#f92672">.</span>append(alias<span style="color:#f92672">.</span>name) self<span style="color:#f92672">.</span>generic_visit(node)<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">report</span>(self): pprint(self<span style="color:#f92672">.</span>stats)

if name == “main”:main()

このコードはいくつかの主要なことを行います。

  1. Pythonファイルのテキスト(この場合はコード例自体)を抽象構文ツリーに変換します。
  2. ASTを分析して、そこからいくつかの情報を抽出します。

このコードは次のように実行できます:

ASTへの変換


2行のコードで、ファイルを読み取り、treeという名前のastを作成します。ast.parse関数はこれを簡単にします!その機能のフードの下で起こっているトンがありますそれは私たちが幸せに無視することができます。

一つの関数呼び出しで、Pythonはすべてのトークンを処理し、言語のすべてのルールに従い、データ構造を構築しました(つまり、 関連するすべての情報を含むツリー)コードを実行する。

先に進む前に、木が何であるかを考えてみましょう。木は非常に深いtopicinのソフトウェア開発である従って徹底的な説明よりprimerratherこれを考慮しなさい。p>

ツリーは、データを”エッジ”で接続された”ノード”のセットを保持する方法です。この図では、A、B、およびCはすべてノードであり、aをBに、AをCに接続するエッジがあります。このツリーをコードで表現する1つの方法は次のとおりです。

class Node: def __init__(self, value): self.value = value self.children = tree = Node('A')tree.children.append(Node('B'))tree.children.append(Node('C'))

treeツリーを操作するとき、実際にはノードのコレクションを扱い、ツリー変数は”ルート”ノード(例えば、ノードA)への参照です。これを行うには、ツリー内の各ノードを訪問し、そのデータを処理します。p>

def print_node_value(value): print(value)def visit(node, handle_node): handle_node(node.value) for child in node.children: visit(child, handle_node)# tree is from the previous example.visit(tree, print_node_value)# This should print:# A# B# C

ツリーが何であるかを考えたので、サンプルスクリプトの次のセクションが何をするかを考えることができます。Pythonの抽象構文ツリーのツリー構造は、ノードの数と格納されているデータの種類のために、より複雑ですが、ノードとエッジのコアアイデアは同じです。ツリーを取得すると、Analyzerは訪問者のパターンに従います。私はPython ASTが私の基本的なNodeast.NodeVisitorが便利な場所です。P>

ANodeVisitorは、Pythonの任意のタイプのノードに応答できますAST.To 特定のタイプのノードを訪問するには、visit_<node type>のように見えるメソッドを実装する必要があります。

私の例のコードは、次のことを見つけようとしています。

imports.To インポートについては、コードはImportImportFromノードタイプからプルします。p>

def visit_Import(self, node): for alias in node.names: self.stats.append(alias.name) self.generic_visit(node)def visit_ImportFrom(self, node): for alias in node.names: self.stats.append(alias.name) self.generic_visit(node)

このコードは、モジュールの名前を取り、統計情報のリストに格納します。コードは派手ではありませんが、ASTノードと対話する方法を示しています。

NodeVisitorクラスが定義されていると、ツリーを分析するためにそれを使用することができます。

analyzer = Analyzer()analyzer.visit(tree)

visitvisit_<node type>メソッドに委譲します。

では、どのような種類のノードタイプがありますか?完全なリストは、astモジュールのドキュメントのabstract Grammarセクションにあります。正直なところ、私はその文書を吸収するのが少し難しいと感じています。あなたはより多くの成功を持っているかもしれませんtheGreen Tree Snakes Nodes guideのようなより網羅的なガイドを参照してください。

ラップアップ

今までに、あなたはうまくいけば、どのように理解しています:

  1. PythonのソースコードからASTを構築します。LI>
  2. を使用してASTの分析を行いますNodeVisitor。私はあなたが抽象構文木を使ってあなたのコードについて多くの興味深い質問に答えることができると思います。次のような質問:
    • 何個の変数を使用しましたか?私のコードで最も一般的な関数呼び出しは何ですか?
    • 私のモジュールは互いに密に結合されていますか?
    • どのサードパーティのライブラリが頻繁に異なるパッケージに表示されますか?

    astモジュールはおそらくあなたが非常に到達するツールではありませんoften.In あなたがastを必要とする時、その最小限のAPIは非常に記憶可能であり、コードを迅速に分析することができます。あなたはこれが有用であることが判明した場合は、Twitterorあなたのお気に入りのソーシャルメディアサイトでこれを共有してもいいですか?

    私はこの種の話題についての人々とチャットするのが好きです。@mblaymanで私をつぶやくこと自由に感じてください。

    Pythonについて学びましょう!DjangoとPythonの詳細を学ぶのを助けるために、1,000人以上の他の開発者と一緒に私のニュースレターに参加することができます。 p>

コメントを残す

メールアドレスが公開されることはありません。