フルパスを指定してモジュールをインポートするにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/67631

質問

フルパスを指定して Python モジュールをロードするにはどうすればよいですか?ファイルは構成オプションであるため、ファイルシステム内のどこにでも置くことができることに注意してください。

役に立ちましたか?

解決

Python 3.5 以降の場合は次を使用します。

import importlib.util
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.MyClass()

Python 3.3 および 3.4 の場合は次を使用します。

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()

(ただし、これは Python 3.4 では非推奨になりました。)

Python 2 の場合は以下を使用します。

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

コンパイルされた Python ファイルおよび DLL には、同等の便利な関数があります。

こちらも参照 http://bugs.python.org/issue21436.

他のヒント

(imp を使用するよりも) sys.path にパスを追加する利点は、単一のパッケージから複数のモジュールをインポートする際の作業が簡素化されることです。例えば:

import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')

from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch

また、次のようなことを実行して、構成ファイルが置かれているディレクトリを Python ロード パスに追加し、ファイルの名前 (この場合は「config」) が事前にわかっていると仮定して、通常のインポートを実行することもできます。

面倒ですが、うまくいきます。

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config

構成ファイルを特にインポートする必要はなく (これには多くの副作用や追加の複雑さが伴います)、単にそれを実行して、結果の名前空間にアクセスできるようにしたいだけのようです。標準ライブラリは、そのための API を次の形式で提供します。 runpy.run_path:

from runpy import run_path
settings = run_path("/path/to/file.py")

このインターフェイスは Python 2.7 および Python 3.2 以降で利用できます。

使用できます

load_source(module_name, path_to_file) 

からのメソッド インプモジュール.

最上位モジュールがファイルではなく、__init__.py を含むディレクトリとしてパッケージ化されている場合、受け入れられた解決策はほぼ機能しますが、完全には機能しません。Python 3.5 以降では、次のコードが必要です (「sys.modules」で始まる追加行に注意してください)。

MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module 
spec.loader.exec_module(module)

この行がないと、exec_module が実行されると、トップレベルの __init__.py 内の相対インポートをトップレベルのモジュール名 (この場合は「mymodule」) にバインドしようとします。ただし、「mymodule」はまだロードされていないため、「SystemError:」というエラーが表示されます。親モジュール「mymodule」がロードされていないため、相対インポートを実行できません。」したがって、ロードする前に名前をバインドする必要があります。この理由は、相対インポート システムの基本的な不変条件です。「不変の保持は、sys.modules['spam'] と sys.modules['spam.foo'] がある場合 (上記のインポート後と同様)、後者は前者の foo 属性として表示される必要があるということです。」 ここで議論されているように.

少し修正したバージョンを思いつきました @SebastianRittau の素晴らしい答え (Python > 3.4 の場合だと思います)。これにより、任意の拡張子を持つファイルをモジュールとしてロードできるようになります。 spec_from_loader の代わりに spec_from_file_location:

from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader 

spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
mod = module_from_spec(spec)
spec.loader.exec_module(mod)

パスを明示的にエンコードする利点 SourceFileLoader それは 機械 拡張子からファイルの種類を判断しようとはしません。これは、次のようなものをロードできることを意味します .txt この方法を使用してファイルを作成することはできませんでしたが、 spec_from_file_location ローダーを指定せずに、 .txt 入っていない importlib.machinery.SOURCE_SUFFIXES.

以下に、2.7 ~ 3.5 のすべての Python バージョン、およびおそらく他のバージョンでも動作するコードをいくつか示します。

config_file = "/tmp/config.py"
with open(config_file) as f:
    code = compile(f.read(), config_file, 'exec')
    exec(code, globals(), locals())

テストしてみました。醜いかもしれませんが、これまでのところ、すべてのバージョンで動作する唯一のものです。

モジュールをインポートするには、そのディレクトリを一時的または永続的に環境変数に追加する必要があります。

一時的に

import sys
sys.path.append("/path/to/my/modules/")
import my_module

永久に

次の行を追加すると、 .bashrc ファイル (Linux の場合) を指定して実行します source ~/.bashrc ターミナル内:

export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"

クレジット/出典: サールル, 別のスタックエクスチェンジの質問

ロードまたはインポートという意味ですか?

sys.path リストを操作してモジュールへのパスを指定し、モジュールをインポートできます。たとえば、次のモジュールがあるとします。

/foo/bar.py

次のことができます:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
def import_file(full_path_to_module):
    try:
        import os
        module_dir, module_file = os.path.split(full_path_to_module)
        module_name, module_ext = os.path.splitext(module_file)
        save_cwd = os.getcwd()
        os.chdir(module_dir)
        module_obj = __import__(module_name)
        module_obj.__file__ = full_path_to_module
        globals()[module_name] = module_obj
        os.chdir(save_cwd)
    except:
        raise ImportError

import_file('/home/somebody/somemodule.py')

使えると信じています imp.find_module() そして imp.load_module() 指定されたモジュールをロードします。パスからモジュール名を分割する必要があります。ロードしたい場合は /home/mypath/mymodule.py 次のようにする必要があります:

imp.find_module('mymodule', '/home/mypath/')

...しかし、これで仕事は完了するはずです。

これは機能するはずです

path = os.path.join('./path/to/folder/with/py/files', '*.py')
for infile in glob.glob(path):
    basename = os.path.basename(infile)
    basename_without_extension = basename[:-3]

    # http://docs.python.org/library/imp.html?highlight=imp#module-imp
    imp.load_source(basename_without_extension, infile)

使用できます pkgutil モジュール (具体的には walk_packages メソッド) を使用して、現在のディレクトリ内のパッケージのリストを取得します。そこから、を使用するのは簡単です importlib 必要なモジュールをインポートするための機械:

import pkgutil
import importlib

packages = pkgutil.walk_packages(path='.')
for importer, name, is_package in packages:
    mod = importlib.import_module(name)
    # do whatever you want with module now, it's been imported!

Python 3.4 のこの領域を理解するのは非常に難しいようです。ただし、Chris Calloway のコードを手始めに少しハッキングしてみると、なんとか動作するようになりました。ここでは基本的な機能を説明します。

def import_module_from_file(full_path_to_module):
    """
    Import a module given the full path/filename of the .py file

    Python 3.4

    """

    module = None

    try:

        # Get module name and path from full path
        module_dir, module_file = os.path.split(full_path_to_module)
        module_name, module_ext = os.path.splitext(module_file)

        # Get module "spec" from filename
        spec = importlib.util.spec_from_file_location(module_name,full_path_to_module)

        module = spec.loader.load_module()

    except Exception as ec:
        # Simple error printing
        # Insert "sophisticated" stuff here
        print(ec)

    finally:
        return module

これは、Python 3.4 の非推奨ではないモジュールを使用しているようです。理由を理解しているつもりはありませんが、プログラム内で機能しているようです。Chris のソリューションはコマンドラインでは機能するが、プログラム内からは機能しないことがわかりました。

それが良いと言っているわけではありませんが、完全を期すために、次のことを提案したいと思います。 exec 関数。Python 2 と 3 の両方で使用できます。exec グローバル スコープまたはディクショナリとして提供される内部スコープで任意のコードを実行できます。

たとえば、モジュールが次の場所に保存されている場合、 "/path/to/module"関数を使用して foo(), 、次のようにして実行できます。

module = dict()
with open("/path/to/module") as f:
    exec(f.read(), module)
module['foo']()

これにより、コードを動的にロードしていることがもう少し明確になり、カスタム組み込み機能を提供する機能などの追加機能が付与されます。

また、キーではなく属性を介してアクセスすることが重要な場合は、そのようなアクセスを提供するグローバルのカスタム dict クラスを設計できます。

class MyModuleClass(dict):
    def __getattr__(self, name):
        return self.__getitem__(name)

指定されたファイル名からモジュールをインポートするには、一時的にパスを拡張し、finally ブロックでシステム パスを復元します。 参照:

filename = "directory/module.py"

directory, module_name = os.path.split(filename)
module_name = os.path.splitext(module_name)[0]

path = list(sys.path)
sys.path.insert(0, directory)
try:
    module = __import__(module_name)
finally:
    sys.path[:] = path # restore

Pythonモジュールtest.pyを作成する

import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3

Pythonモジュールtest_check.pyを作成する

from test import Client1
from test import Client2
from test import test3

インポートしたモジュールを module からインポートできます。

を使ったパッケージを作りました imp あなたのために。私はそれを呼びます import_file そしてこれはそれがどのように使用されるかです:

>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')

以下で入手できます。

http://pypi.python.org/pypi/import_file

または

http://code.google.com/p/import-file/

実行時にパッケージモジュールをインポートする (Python レシピ)

http://code.activestate.com/recipes/223972/

###################
##                #
## classloader.py #
##                #
###################

import sys, types

def _get_mod(modulePath):
    try:
        aMod = sys.modules[modulePath]
        if not isinstance(aMod, types.ModuleType):
            raise KeyError
    except KeyError:
        # The last [''] is very important!
        aMod = __import__(modulePath, globals(), locals(), [''])
        sys.modules[modulePath] = aMod
    return aMod

def _get_func(fullFuncName):
    """Retrieve a function object from a full dotted-package name."""

    # Parse out the path, module, and function
    lastDot = fullFuncName.rfind(u".")
    funcName = fullFuncName[lastDot + 1:]
    modPath = fullFuncName[:lastDot]

    aMod = _get_mod(modPath)
    aFunc = getattr(aMod, funcName)

    # Assert that the function is a *callable* attribute.
    assert callable(aFunc), u"%s is not callable." % fullFuncName

    # Return a reference to the function itself,
    # not the results of the function.
    return aFunc

def _get_class(fullClassName, parentClass=None):
    """Load a module and retrieve a class (NOT an instance).

    If the parentClass is supplied, className must be of parentClass
    or a subclass of parentClass (or None is returned).
    """
    aClass = _get_func(fullClassName)

    # Assert that the class is a subclass of parentClass.
    if parentClass is not None:
        if not issubclass(aClass, parentClass):
            raise TypeError(u"%s is not a subclass of %s" %
                            (fullClassName, parentClass))

    # Return a reference to the class itself, not an instantiated object.
    return aClass


######################
##       Usage      ##
######################

class StorageManager: pass
class StorageManagerMySQL(StorageManager): pass

def storage_object(aFullClassName, allOptions={}):
    aStoreClass = _get_class(aFullClassName, StorageManager)
    return aStoreClass(allOptions)

Linux では、Python スクリプトが配置されているディレクトリにシンボリック リンクを追加すると機能します。

つまり:

ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py

Python が作成します /absolute/path/to/script/module.pyc 内容を変更すると更新されます /absolute/path/to/module/module.py

次に、mypythonscript.py に以下を含めます

from module import *

非常に簡単な方法:相対パス ../../MyLibs/pyfunc.py を使用してファイルをインポートしたいとします。


libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf

しかし、ガードなしで成功すると、最終的に非常に長いパスを得ることができます

を使用した簡単な解決策 importlib の代わりに imp パッケージ (Python 2.7 でテスト済みですが、Python 3 でも動作するはずです):

import importlib

dirname, basename = os.path.split(pyfilepath) # pyfilepath: '/my/path/mymodule.py'
sys.path.append(dirname) # only directories should be added to PYTHONPATH
module_name = os.path.splitext(basename)[0] # '/my/path/mymodule.py' --> 'mymodule'
module = importlib.import_module(module_name) # name space of defined module (otherwise we would literally look for "module_name")

これで、次のように、インポートされたモジュールの名前空間を直接使用できるようになります。

a = module.myvar
b = module.myfunc(a)

このソリューションの利点は、 インポートしたいモジュールの実際の名前を知る必要さえありません。, 、コードで使用するために。これは便利です。モジュールのパスが構成可能な引数である場合。

うまくいくものが見つからなかったので、これを回答リストに追加します。これにより、3.4 でコンパイル済み (pyd) Python モジュールをインポートできるようになります。

import sys
import importlib.machinery

def load_module(name, filename):
    # If the Loader finds the module name in this list it will use
    # module_name.__file__ instead so we need to delete it here
    if name in sys.modules:
        del sys.modules[name]
    loader = importlib.machinery.ExtensionFileLoader(name, filename)
    module = loader.load_module()
    locals()[name] = module
    globals()[name] = module

load_module('something', r'C:\Path\To\something.pyd')
something.do_something()

この回答は、コメントに対する Sebastian Rittau の回答の補足です。「しかし、モジュール名がない場合はどうなりますか?」これは、ファイル名を与えられた可能性のあるPythonモジュール名を取得するための迅速で汚い方法です。 __init__.py ファイルを作成し、それをファイル名に戻します。Python 3.4 以降 (pathlib を使用) の場合、Py2 の人は「imp」または相対インポートを行う他の方法を使用できるため、これは理にかなっています。

import pathlib

def likely_python_module(filename):
    '''
    Given a filename or Path, return the "likely" python module name.  That is, iterate
    the parent directories until it doesn't contain an __init__.py file.

    :rtype: str
    '''
    p = pathlib.Path(filename).resolve()
    paths = []
    if p.name != '__init__.py':
        paths.append(p.stem)
    while True:
        p = p.parent
        if not p:
            break
        if not p.is_dir():
            break

        inits = [f for f in p.iterdir() if f.name == '__init__.py']
        if not inits:
            break

        paths.append(p.stem)

    return '.'.join(reversed(paths))

確かに改善の可能性はありますが、オプションの __init__.py ファイルによっては他の変更が必要になる場合がありますが、 __init__.py 一般に、これでうまくいきます。

最良の方法は、公式ドキュメントから入手することだと思います (29.1。imp — インポート内部にアクセスする):

import imp
import sys

def __import__(name, globals=None, locals=None, fromlist=None):
    # Fast path: see if the module has already been imported.
    try:
        return sys.modules[name]
    except KeyError:
        pass

    # If any of the following calls raises an exception,
    # there's a problem we can't handle -- let the caller handle it.

    fp, pathname, description = imp.find_module(name)

    try:
        return imp.load_module(name, fp, pathname, description)
    finally:
        # Since we may exit via an exception, close fp explicitly.
        if fp:
            fp.close()
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top