私はPython 3用の«モジュールエキスパンダー»ツールを開発しようとしましたが、いくつか問題があります。Pythonモジュールをインポートせずに模倣する方法は?
与えられたPythonスクリプトmain.py
の場合、ツールは機能的に同等のPythonスクリプトexpanded_main.py
を生成します。各インポート文は、インポートされたモジュールの実際のコードで置き換えられます。これは、インポートされたPythonのソースコードがアクセス可能であることを前提としています。正しい方法で仕事をするには、Pythonの組み込みモジュールast
と、astor
というサードパーティのツールを使って、ASTをPythonソースにダンプすることができます。このインポートエキスパンダーの動機は、スクリプトを1つのバイトコードチャンクにコンパイルすることができるようにするためです。Python VMはモジュールのインポートを考慮してはいけません(MicroPythonなどでは便利です)。
最も単純なケースは、文です:これを変換するために
from import my_module1 import *
、私のツールは、ファイルmy_module1.py
を探し、それがこのファイルの内容によってimport文を置き換えます。次に、expanded_main.py
は、モジュールが通常の方法でインポートされたかのように、my_module
で定義されている任意の名前にアクセスできます。私はトリックを明らかにする可能性のある微妙な副作用は気にしない。また、簡略化するために、以前のインポート(アスタリスク付き)としてfrom import my_module1 import a, b, c
を扱い、副作用の可能性については考慮していません。ここまでは順調ですね。
ここに私の要点があります。インポートのこの味を扱うことができる方法:
class my_module2:
# content of my_module2.py
…
:私の最初のアイデアはインデントPythonのファイルの内容をモジュールと同じ名前を持つクラスを作成してコピーすることによって、これを模倣した
import my_module2
これは実際には多くの場合動作しますが、悲しいことに、これにはいくつかの不具合があることが判明しました。その1つは、モジュールで定義されたグローバル変数を参照する本体を持つ関数で失敗したことです。たとえば、次の2つのPythonのファイルを考えてみます。
# my_module2.py
g = "Hello"
def greetings():
print (g + " World!")
と実行時
# main.py
import my_module2
print(my_module2.g)
my_module2.greetings()
、
main.py
プリント
"Hello"
と
"Hello World!"
。さて、私のエキスパンダーツールは、これを生成しなければならない。
expanded_main.py
の実行時に
# expanded_main.py
class my_module2:
g = "Hello"
def greetings():
print (g + " World!")
print(my_module2.g)
my_module2.greetings()
を、最初のprint文はOKです("Hello"
)が、挨拶機能は、例外が発生します:NameError: name 'g' is not defined
。実際に何が起こる はモジュールmy_module2
で
- 、
g
がでグローバル変数、 - があるということであるクラス
my_module2
は、g
がmy_module2.g
と呼ばれるべきクラス変数、です。あなたは関数、クラス、...my_module2.py
中を定義し、他の関数、クラス、...同じmy_module2.py
の中でそれらを参照したい場合
他の同様の副作用が起こります。
これらの問題がどのように解決できるか考えてみましょうか?
モジュールを模倣できる他のPython構造体はありますか?
最後の注意:私は、ツールがネストされたインポート(再帰)の1度を気にして、同じモジュールの2倍の多重インポートに注意することを知っています。私はこれらの話題についてここでは議論するつもりはないと思う。
@Ignacio:私のメッセージで述べたように、Python * 3 *です。まあ、私は3.4と3.6でこれをテストしました。私はPython 2では、例外が異なっていることを知っています(「TypeError:unboundメソッドのgreetings()は、少なくともPython 2.6で、my_module2インスタンスを最初の引数として(何も持っていません)」と呼び出さなければなりません)。 –
なぜあなたはこれをやっていますか? –
@Chris;その目的は自己完結型スクリプトを用意して、自己完結型のPythonバイトコードファイルにコンパイルできるようにすることです。これを実行するには、実行時にPythonのimportiロジックに依存する必要はありません。ファイルシステムにアクセスすることもできません。これは、リソースが制約されているシステム(マイクロコントローラ上のMicroPythonなど)に役立ちます。 –