フルパスを指定してモジュールをインポートする方法は?


1141

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


21
素晴らしくシンプルな質問-便利な答えですが、Pythonのマントラで何が起こったのかを疑問視するようになりました。「明確な方法が1つ あります」。 。そのような基本的な操作は、途方もなくハッキーでバージョンに依存しているようです(そして、新しいバージョンでは見た目も肥大化しています)。
inger

回答:


1282

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も参照してください。


53
名前空間を知っている場合-'module.name'-私はすでに使用しています__import__
Sridhar Ratnakumar、2009

62
@SridharRatnakumarの最初の引数の値は、返されるモジュールのをimp.load_source設定するだけ.__name__です。読み込みには影響しません。
Dan D.

17
@DanD。—の最初の引数はimp.load_source()sys.modulesディクショナリに作成される新しいエントリのキーを決定するため、最初の引数は実際にロードに影響します。
Brandon Rhodes

9
impモジュールは、バージョン3.4で廃止されました:impパッケージはの賛成で廃止を保留していますimportlib
Chiel ten Brinke、2013

9
@AXOやもっと多くの点で、なぜこれほど単純で基本的なものが非常に複雑でなければならないのか不思議に思います。他の多くの言語にはありません。
岩だらけの

423

(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

13
sys.path.appendディレクトリではなく単一のpythonファイルを指すにはどうすればよいですか?
Phani

28
:-)おそらく、あなたの質問は、回答に対するコメントではなく、StackOverflowの質問として適しています。
ダリルスピッツァー2015年

3
Pythonパスには、zipアーカイブ、「eggs」(複雑な種類のzipアーカイブ)などを含めることができます。モジュールは、それらからインポートできます。したがって、パス要素は実際はファイルのコンテナですが、必ずしもディレクトリである必要はありません。
アレクシス2015

12
Pythonがimportステートメントをキャッシュするという事実に注意してください。1つのクラス名(classX)を共有する2つの異なるフォルダーがあるというまれなケースでは、sys.pathにパスを追加し、classXをインポートし、パスを削除して、残りのパスに対して繰り返すというアプローチは機能しません。Pythonは常に、そのキャッシュから最初のパスからクラスをロードします。私の場合、すべてのプラグインが特定のclassXを実装するプラグインシステムを作成することを目指しました。最終的にSourceFileLoaderを使用しました。その非推奨については議論の余地があることに注意してください。
ComFreek

3
このアプローチでは、インポートされたモジュールが同じディレクトリから他のモジュールをインポートできるようになりますが、モジュールはしばしばそうしますが、受け入れられた回答のアプローチはそうではありません(少なくとも3.7)。importlib.import_module(mod_name)実行時にモジュール名がわからない場合は、ここで明示的なインポートの代わりに使用できますがsys.path.pop()、最後にを追加します。ただし、インポートされたコードが使用中のモジュールをさらにインポートしようとしない場合。
Eli_B

43

トップレベルのモジュールがファイルではなく、__ 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属性として表示される必要があります」ここで説明ます


どうもありがとう!このメソッドは、サブモジュール間の相対的なインポートを可能にします。すごい!
テバネップ

この回答は、ドキュメントdocs.python.org/3/library/…に一致します。
Tim Ludwinski、

1
しかし、何mymoduleですか?
Gulzar

@Gulzar、それはあなたがあなたのモジュールに付けたい名前で、後でできるようになります: "from mymodule import myclass"
Idodo

だから... ... /path/to/your/module/実際にありますか/path/to/your/PACKAGE/?とmymoduleはどういう意味myfile.pyですか?
Gulzar

37

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

一時的に

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

永久に

次の行を.bashrcファイルに追加して(Linuxの場合)source ~/.bashrc、ターミナルで実行します。

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

クレジット/ソース:saarrrr別のstackexchangeの質問


3
この「一時」ソリューションは、Jupyterノートブックでプロジェクトを他の場所で作成したい場合に最適です。
Fordy、

しかし...それは道を改ざんするのは危険です
Shai Alon

@ShaiAlonパスを追加しているので、あるコンピュータから別のコンピュータにコードを転送するとき以外は、パスがめちゃくちゃになる可能性があります。したがって、パッケージ開発では、ローカルパッケージのみをインポートします。また、パッケージ名は一意である必要があります。心配な場合は、一時的な解決策を使用してください。
Miladiouss

28

構成ファイル(大量の副作用と追加の複雑な処理が含まれている)を具体的にインポートするのではなく、単に実行して、結果の名前空間にアクセスできるようにする必要があるようです。標準ライブラリは、そのためのAPIをrunpy.run_pathの形式で提供します。

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

そのインターフェースはPython 2.7とPython 3.2以降で利用できます


私はこの方法が好きですが、run_pathの結果を取得すると、アクセスできないように見える辞書ですか?
Stephen Ellwood 2018

「アクセスできない」とはどういう意味ですか?あなたがすることはできません(これはインポートスタイルのアクセスが実際に必要とされていない唯一の良い選択肢である理由です)、それからの輸入が、その内容は、(通常のdictのAPIを介して利用可能であるべきresult[name]result.get('name', default_value)など、)
ncoghlan

この答えはかなり過小評価されています。とても短くてシンプルです!さらに良いことに、適切なモジュール名前空間が必要な場合は、次のようなことができます from runpy import run_path; from argparse import Namespace; mod = Namespace(**run_path('path/to/file.py'))
RuRo

20

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

乱雑ですが、動作します。

configfile = '~/config.py'

import os
import sys

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

import config

それは動的ではありません。
Shai Alon、

私が試した:config_file = 'setup-for-chats'、setup_file = get_setup_file(config_file + ".py")、sys.path.append(os.path.dirname(os.path.expanduser(setup_file)))、import config_file >> "ImportError:No module named config_file"
Shai Alon


13
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')

37
標準ライブラリですでに対処されているのに、なぜ14行のバグのあるコードを書くのですか?full_path_to_moduleまたはos.whateverオペレーションのフォーマットまたはコンテンツのエラーチェックを行っていません。そして、catch-all except:句を使用することはめったにありません。
Chris Johnson

ここでは、「try-finally」をさらに使用する必要があります。例save_cwd = os.getcwd() try: … finally: os.chdir(save_cwd)
わかりました-SEは邪悪です

11
@ChrisJohnson this is already addressed by the standard libraryそうですが、Pythonには下位互換性がないという厄介な癖があります...チェックされた答えは3.3の前後に2つの異なる方法があると言っているからです。その場合は、バージョンをオンザフライでチェックするのではなく、独自のユニバーサル関数を記述したいです。そして、はい、このコードはエラー保護が十分ではないかもしれませんが、より良いコードを書くことができるという根拠に基づいて(os.chdir()ですが、考えていません)のアイデアを示しています。したがって、+ 1。
Sushi271

13

これは、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())

私はそれをテストしました。醜いかもしれませんが、これまでのところ、すべてのバージョンで機能するのはこれだけです。


1
この回答load_sourceは、スクリプトをインポートし、インポート時にモジュールおよびグローバルへのスクリプトアクセスを提供するため、うまくいきませんでした。
Klik

13

私は少しの修正版が出ているSebastianRittauの素晴らしい答え@あなたが使用してモジュールとして任意の拡張子を持つファイルをロードできるようになります(パイソン> 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


13

ロードまたはインポートを意味しますか?

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

/foo/bar.py

あなたはできる:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar

1
@Wheat sys.path [0]ではなくsys.path [0:0]を使用する理由
user618677 2012年

5
B / c sys.path [0] = xyは最初のパス項目を上書きしますが、path [0:0] = xyはpath.insert(0、xy)と同等です
dom0

2
hm the path.insertはうまくいきましたが、[0:0]トリックはうまくいきませんでした。
jsh 2013

11
sys.path[0:0] = ['/foo']
Kevin Edwards、

6
Explicit is better than implicit.では、なぜではsys.path.insert(0, ...)なくsys.path[0:0]
winklerrr

8

指定したモジュールを使用imp.find_module()imp.load_module()てロードできると思います。モジュール名をパスから分割する必要があります。つまり、ロード/home/mypath/mymodule.pyする場合は、次のようにする必要があります。

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

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


6

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!

5

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

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


4

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のソリューションはコマンドラインで機能しましたが、プログラム内では機能しませんでした。


4

私はそれがより良いと言っているわけではありませんが、完全を期すため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)

4

指定されたファイル名からモジュールをインポートするには、一時的にパスを拡張し、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

3

これはうまくいくはずです

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)

4
拡張を切り取るより一般的な方法は次のとおりname, ext = os.path.splitext(os.path.basename(infile))です。以前の.py拡張子の制限により、メソッドが機能します。また、おそらくいくつかの変数/辞書エントリにモジュールをインポートする必要があります。
ReneSac

3

スクリプトが同じプロジェクトにあるが、ディレクトリが異なる場合は、次の方法でこの問題を解決できます。

この状況utils.pyではsrc/main/util/

import sys
sys.path.append('./')

import src.main.util.utils
#or
from src.main.util.utils import json_converter # json_converter is example method

2

を使ったパッケージを作りました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/


1
os.chdir?(コメントを承認するための最小限の文字)。
ychaouche 2012年

pyinstallerで生成されたexeのインポートバグのトラブルシューティングを1日中行ってきました。結局これは私のために働いた唯一のものです。これを作ってくれてありがとう!
frakman1

2

実行時にパッケージモジュールをインポートする(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)

2

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

つまり:

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

/absolute/path/to/script/module.pycの内容を変更すると、pythonが作成して更新します/absolute/path/to/module/module.py

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

from module import *

1
これは私が使用したハックであり、いくつかの問題を引き起こしています。さらに苦痛なことの1つは、IDEAがリンク内から変更されたコードを取得しないが、そこにあると考えているものを保存しようとする問題があることです。最後に保存する必要のある競合状態...これが原因で、かなりの量の作業が失われました。
グリップ2016年

@Gripp私はあなたの問題を理解しているかどうかわかりませんが、Cyber​​Duckのようなクライアントを使用して、SFTP経由でデスクトップからリモートサーバー上のスクリプトを頻繁に(ほぼ例外なく)編集します。その場合も、シンボリックリンクされたファイルを編集します。元のファイルを編集する方がはるかに安全です。を使用gitしてチェックgit statusし、スクリプトへの変更が実際にソースドキュメントに戻っており、etherで失われていないことを確認することで、これらの問題の一部をキャッチできます。
user5359531 2017

2

importlibモジュールに基づいて、次の目的で独自のグローバルでポータブルなインポート関数を記述しました。

  • 両方のモジュールをサブモジュールとしてインポートし、モジュールのコンテンツを親モジュール(または親モジュールがない場合はグローバル)にインポートできます。
  • ファイル名にピリオド文字を含むモジュールをインポートできるようになりました。
  • 任意の拡張子を持つモジュールをインポートできるようにします。
  • デフォルトの拡張子のないファイル名の代わりに、サブモジュールのスタンドアロン名を使用できるようにします。
  • sys.path検索パスのストレージに依存したり、依存したりする代わりに、以前にインポートされたモジュールに基づいてインポート順序を定義できるようになります。

ディレクトリ構造の例:

<root>
 |
 +- test.py
 |
 +- testlib.py
 |
 +- /std1
 |   |
 |   +- testlib.std1.py
 |
 +- /std2
 |   |
 |   +- testlib.std2.py
 |
 +- /std3
     |
     +- testlib.std3.py

包含の依存関係と順序:

test.py
  -> testlib.py
    -> testlib.std1.py
      -> testlib.std2.py
    -> testlib.std3.py 

実装:

最新の変更ストア:https : //sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/python/tacklelib/tacklelib.py

test.py

import os, sys, inspect, copy

SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("test::SOURCE_FILE: ", SOURCE_FILE)

# portable import to the global space
sys.path.append(TACKLELIB_ROOT) # TACKLELIB_ROOT - path to the library directory
import tacklelib as tkl

tkl.tkl_init(tkl)

# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()

tkl_import_module(SOURCE_DIR, 'testlib.py')

print(globals().keys())

testlib.base_test()
testlib.testlib_std1.std1_test()
testlib.testlib_std1.testlib_std2.std2_test()
#testlib.testlib.std3.std3_test()                             # does not reachable directly ...
getattr(globals()['testlib'], 'testlib.std3').std3_test()     # ... but reachable through the `globals` + `getattr`

tkl_import_module(SOURCE_DIR, 'testlib.py', '.')

print(globals().keys())

base_test()
testlib_std1.std1_test()
testlib_std1.testlib_std2.std2_test()
#testlib.std3.std3_test()                                     # does not reachable directly ...
globals()['testlib.std3'].std3_test()                         # ... but reachable through the `globals` + `getattr`

testlib.py

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("1 testlib::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/std1', 'testlib.std1.py', 'testlib_std1')

# SOURCE_DIR is restored here
print("2 testlib::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/std3', 'testlib.std3.py')

print("3 testlib::SOURCE_FILE: ", SOURCE_FILE)

def base_test():
  print('base_test')

testlib.std1.py

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std1::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/../std2', 'testlib.std2.py', 'testlib_std2')

def std1_test():
  print('std1_test')

testlib.std2.py

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std2::SOURCE_FILE: ", SOURCE_FILE)

def std2_test():
  print('std2_test')

testlib.std3.py

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std3::SOURCE_FILE: ", SOURCE_FILE)

def std3_test():
  print('std3_test')

出力3.7.4):

test::SOURCE_FILE:  <root>/test01/test.py
import : <root>/test01/testlib.py as testlib -> []
1 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE:  <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE:  <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE:  <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib'])
base_test
std1_test
std2_test
std3_test
import : <root>/test01/testlib.py as . -> []
1 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE:  <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE:  <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE:  <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib', 'testlib_std1', 'testlib.std3', 'base_test'])
base_test
std1_test
std2_test
std3_test

Pythonでテスト済み3.7.43.2.52.7.16

長所

  • 両方のモジュールをサブモジュールとしてインポートでき、モジュールのコンテンツを親モジュール(または親モジュールがない場合はグローバル)にインポートできます。
  • ファイル名にピリオドを含むモジュールをインポートできます。
  • 任意の拡張モジュールから任意の拡張モジュールをインポートできます。
  • デフォルトである拡張子なしのファイル名(たとえば、testlib.std.pyas testlibtestlib.blabla.pyas testlib_blablaなど)の代わりに、サブモジュールのスタンドアロン名を使用できます。
  • sys.path検索パスストレージに依存しません。
  • の呼び出しのようSOURCE_FILESOURCE_DIR、呼び出しの間にグローバル変数を保存/復元する必要はありませんtkl_import_module
  • [ 3.4.x以上]ネストされたtkl_import_module呼び出しでモジュールの名前空間を混在させることができます(例:named->local->namedなどlocal->named->local)。
  • [ 3.4.x以上]宣言された場所からtkl_import_moduletkl_declare_global関数を介して)インポートされたすべての子モジュールにグローバル変数/関数/クラスを自動エクスポートできます。

短所

  • [ 3.3.x以下] tkl_import_moduleを呼び出すすべてのモジュールで宣言する必要がありますtkl_import_module(コードの複製)

アップデート1,2(for3.4.x以降のみ):

Python 3.4以降では、宣言することtkl_import_moduleで各モジュールで宣言する要件をバイパスできますtkl_import_moduleは、最上位、関数は1回の呼び出しですべての子モジュールにそれ自体を挿入します(これは一種の自己展開インポートです)。

アップデート3

インポート時にサポート実行ガードを備えtkl_source_moduleたbashにアナログとして関数を追加しましたsource(インポートの代わりにモジュールマージを介して実装)。

アップデート4

tkl_declare_globalモジュールグローバル変数が子モジュールの一部ではないためモジュールグローバル変数が表示されないすべての子モジュールに、モジュールグローバル変数を自動エクスポートする機能が追加されました。

アップデート5

すべての関数は、tacklelibライブラリに移動しました。上のリンクを参照してください。


2

これに特化したパッケージがあります

from thesmuggler import smuggle

# À la `import weapons`
weapons = smuggle('weapons.py')

# À la `from contraband import drugs, alcohol`
drugs, alcohol = smuggle('drugs', 'alcohol', source='contraband.py')

# À la `from contraband import drugs as dope, alcohol as booze`
dope, booze = smuggle('drugs', 'alcohol', source='contraband.py')

Pythonのバージョン(JythonとPyPyも)でテストされていますが、プロジェクトのサイズによってはやり過ぎになる場合があります。


1

うまくいったものが見つからなかったので、これを回答のリストに追加しました。これにより、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()

1

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


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

しかし、あなたが警備員なしでそれを作るならば、あなたは最終的に非常に長い道を得ることができます


1

パッケージの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)

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


このようにしてsys.path、すべてのユースケースに適合しないを変更します。
bgusach

@bgusachこれは本当かもしれませんが、場合によっては望ましいこともあります(sys.pathにパスを追加すると、単一のパッケージから複数のモジュールをインポートする場合の処理​​が簡単になります)。とにかく、これが望ましくない場合は、すぐに行うことができますsys.path.pop()
アタキシア

0

この回答は、コメントに対する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一般的に持っているならば、これはトリックをします。


-1

最良の方法は、公式ドキュメントからのものだと思います(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()

1
このソリューションでは、質問が要求するパスを提供することはできません。
Micah Smith
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.