web-dev-qa-db-ja.com

名前をつけてモジュールをインポートするにはどうすればいいですか?

引数としてコマンドを受け取る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()

これは問題なく動作します。このコードを使って行っていることを達成するためのもっと慣用的な方法があるかどうか、私は思っています。

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

442
Kamil Kisiel

2.7/3.1より古いPythonでは、それはほとんどあなたがそうする方法です。

新しいバージョンについては、 Python 2 および Python 3importlib.import_moduleを参照してください。

必要に応じてexecを使うこともできます。

あるいは__import__を使ってこれを行うことでモジュールのリストをインポートすることができます:

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

Dive Into Python から直接リッピングしました。

270
Harley Holcombe

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

importlib.import_module(name、package = None)

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

例えば.

my_module = importlib.import_module('os.path')
262

注: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
127
monkut

impモジュール 、またはもっと直接的な __import__() 関数を使用してください。

19
gimel

あなたがあなたの地元の人々にそれを望むならば:

>>> 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()でも同じことが言えます

13
Jonathan

あなたは exec を使うことができます:

exec "import myapp.commands.%s" % command
10
Greg Hewgill

今日では importlib を使うべきです。

ソースファイルをインポートする

のドキュメント は実際にそのレシピを提供しています、そしてそれは次のようになります:

import sys
import importlib.util

file_path = 'pluginX.py'
module_name = 'pluginX'

spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)

# check if it's all there..
def bla(mod):
    print(dir(mod))
bla(module)

パッケージをインポートする

現在のディレクトリにパッケージをインポートする(例:pluginX/__init__.py)は、実際には簡単です。

import importlib

pluginX = importlib.import_module('pluginX')

# check if it's all there..
def bla(mod):
    print(dir(mod))
bla(module)
4
Brandt

@monkutのソリューションと似ていますが、ここで説明されている再利用可能でエラー耐性があります http://stamat.wordpress.com/dynamic-module-import-in-python/

import os
import imp

def importFromURI(uri, absl):
    mod = None
    if not absl:
        uri = os.path.normpath(os.path.join(os.path.dirname(__file__), uri))
    path, fname = os.path.split(uri)
    mname, ext = os.path.splitext(fname)

    if os.path.exists(os.path.join(path,mname)+'.pyc'):
        try:
            return imp.load_compiled(mname, uri)
        except:
            pass
    if os.path.exists(os.path.join(path,mname)+'.py'):
        try:
            return imp.load_source(mname, uri)
        except:
            pass

    return mod
3
stamat

例:私のモジュール名はjan_module/feb_module/mar_moduleのようになります。

月= 'feb'
exec 'from%s_module import *'%(月)

1
chiru

それはあなたが本当に欲しいものがプラグインアーキテクチャであるように聞こえます。

Setuptoolsパッケージが提供する エントリポイント の機能を見てください。それはあなたのアプリケーションのためにロードされているプラ​​グインを発見するための素晴らしい方法を提供します。

1
dowski

下の部分は私のために働きました:

>>>import imp; 
>>>fp, pathname, description = imp.find_module("/home/test_module"); 
>>>test_module = imp.load_module("test_module", fp, pathname, description);
>>>print test_module.print_hello();

あなたがシェルスクリプトでインポートしたい場合:

python -c '<above entire code in one line>'
0
PanwarS87