620

私は、引数としてコマンドを受け取るPythonアプリケーションを書いています。次に例を示します。

$ python myapp.py command1

アプリケーションを拡張可能にする、つまり、メインのアプリケーションソースを変更せずに、新しいコマンドを実装する新しいモジュールを追加できるようにする必要があります。ツリーは次のようになります。

myapp/
    __init__.py
    commands/
        __init__.py
        command1.py
        command2.py
    foo.py
    bar.py

したがって、アプリケーションが実行時に使用可能なコマンドモジュールを見つけて、適切なコマンドモジュールを実行するようにします。

Pythonは、モジュール名の文字列を受け取る__import__関数を定義します。

__import __(name、globals = None、locals = None、fromlist =()、level = 0)

この関数はモジュール名をインポートし、パッケージコンテキストで名前を解釈する方法を決定するために、指定されたグローバルとローカルを使用する可能性があります。fromlistは、nameで指定されたモジュールからインポートする必要があるオブジェクトまたはサブモジュールの名前を示します。

ソース:https ://docs.python.org/3/library/functions.html# import

だから現在私は次のようなものを持っています:

command = sys.argv[1]
try:
    command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
    # Display error message

command_module.run()

これは問題なく機能します。このコードで行っていることを達成するためのもっと慣用的な方法があるのではないかと思っています。

私は特に卵や拡張ポイントの使用に乗り込みたくないことに注意してください。これはオープンソースプロジェクトではなく、「プラグイン」があるとは思いません。重要なのは、メインアプリケーションコードを簡素化し、新しいコマンドモジュールが追加されるたびにコードを変更する必要をなくすことです。

4

10 に答える 10

370

2.7 / 3.1より古いPythonでは、それがほとんどの方法です。

新しいバージョンについてはimportlib.import_modulePython2およびPython3を参照してください。

必要に応じて使用することもできますexec

または、__import__次のようにしてモジュールのリストをインポートできます。

>>> moduleNames = ['sys', 'os', 're', 'unittest'] 
>>> moduleNames
['sys', 'os', 're', 'unittest']
>>> modules = map(__import__, moduleNames)

DiveIntoPythonから直接リッピングしました。

于 2008-11-19T06:17:18.687 に答える
355

Python 2.7および3.1以降で推奨される方法は、importlibモジュールを使用することです。

importlib.import_module(name、package = None)

モジュールをインポートします。name引数は、どのモジュールを絶対的または相対的な用語でインポートするかを指定します(たとえば、pkg.modまたは..modのいずれか)。名前が相対的な用語で指定されている場合、パッケージ引数は、パッケージ名を解決するためのアンカーとして機能するパッケージの名前に設定する必要があります(例:import_module('.. mod'、'pkg.subpkg') pkg.modをインポートします)。

例えば

my_module = importlib.import_module('os.path')
于 2012-12-22T07:33:46.093 に答える
136

注: impは、Python 3.4 以降、importlibを支持して廃止されました。

前述のように、impモジュールはロード機能を提供します。

imp.load_source(name, path)
imp.load_compiled(name, path)

これらを以前に使用して、同様のことを実行しました。

私の場合、必要なメソッドが定義された特定のクラスを定義しました。モジュールをロードしたら、クラスがモジュール内にあるかどうかを確認し、そのクラスのインスタンスを次のように作成します。

import imp
import os

def load_from_file(filepath):
    class_inst = None
    expected_class = 'MyClass'

    mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1])

    if file_ext.lower() == '.py':
        py_mod = imp.load_source(mod_name, filepath)

    elif file_ext.lower() == '.pyc':
        py_mod = imp.load_compiled(mod_name, filepath)

    if hasattr(py_mod, expected_class):
        class_inst = getattr(py_mod, expected_class)()

    return class_inst
于 2008-11-19T08:21:25.567 に答える
20

imp モジュール、またはより直接的な関数を使用し__import__()ます。

于 2008-11-19T06:28:28.960 に答える
14

ローカルでそれが必要な場合:

>>> mod = 'sys'
>>> locals()['my_module'] = __import__(mod)
>>> my_module.version
'2.6.6 (r266:84297, Aug 24 2010, 18:46:32) [MSC v.1500 32 bit (Intel)]'

同じように動作しますglobals()

于 2011-11-06T17:08:08.677 に答える
12

あなたが使用することができますexec

exec("import myapp.commands.%s" % command)
于 2008-11-19T06:12:54.747 に答える
-8

以下は私のために働いた:

import sys, glob
sys.path.append('/home/marc/python/importtest/modus')
fl = glob.glob('modus/*.py')
modulist = []
adapters=[]
for i in range(len(fl)):
    fl[i] = fl[i].split('/')[1]
    fl[i] = fl[i][0:(len(fl[i])-3)]
    modulist.append(getattr(__import__(fl[i]),fl[i]))
    adapters.append(modulist[i]())

モジュールは「modus」フォルダからロードされます。モジュールには、モジュール名と同じ名前の単一のクラスがあります。たとえば、ファイル modus/modu1.py には以下が含まれます。

class modu1():
    def __init__(self):
        self.x=1
        print self.x

結果は、動的にロードされたクラス「アダプター」のリストです。

于 2010-08-20T08:24:14.593 に答える