전체 경로가 주어진 모듈을 가져 오는 방법은 무엇입니까?


1139

전체 경로가 주어진 파이썬 모듈을 어떻게로드 할 수 있습니까? 파일은 구성 옵션이므로 파일 시스템의 어느 위치 에나있을 수 있습니다.


21
훌륭하고 간단한 질문-그리고 유용한 답변이지만 파이썬 만트라에서 어떤 일이 일어 났는지 궁금해 합니다. " 한가지 확실한 방법이 있습니다." 그러한 기본적인 작업을 위해 말도 안되게 해킹되고 버전에 의존하는 것 같습니다 (그리고 새로운 버전에서는 더 부풀어 보입니다.).
inger December

답변:


1281

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에서는 더 이상 사용되지 않습니다.)

파이썬 2의 경우 :

import imp

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

컴파일 된 파이썬 파일과 DLL에 대해 동등한 편의 기능이 있습니다.

http://bugs.python.org/issue21436 도 참조하십시오 .


53
네임 스페이스 'module.name'을 알고 있다면 이미 사용하고 있습니다 __import__.
Sridhar Ratnakumar

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

9
@AXO 간단한 기본으로 뭔가이 같은 이유는 더 많은 지점에 하나 개의 불가사의 너무 복잡합니다. 다른 많은 언어는 아닙니다.
rocky

422

sys.path에 경로를 추가하면 (imp를 사용하여) 단일 패키지에서 둘 이상의 모듈을 가져올 때 작업을 단순화한다는 이점이 있습니다. 예를 들면 다음과 같습니다.

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디렉토리 대신 단일 파이썬 파일을 가리키는 데 어떻게 사용 합니까?
Phani

28
:-) 아마도 귀하의 질문은 답변에 대한 의견이 아니라 StackOverflow 질문에 더 적합 할 것입니다.
Daryl Spitzer

3
파이썬 경로에는 zip 아카이브, "계란"(복잡한 종류의 zip 아카이브) 등이 포함될 수 있습니다. 모듈을 가져올 수 있습니다. 따라서 경로 요소는 실제로 파일의 컨테이너 이지만 반드시 디렉토리는 아닙니다.
alexis

12
Python이 import 문을 캐시한다는 사실에주의하십시오. 드문 경우이지만 단일 클래스 이름 (classX)을 공유하는 두 개의 다른 폴더가있는 경우 sys.path에 경로를 추가하고, classX를 가져오고, 경로를 제거하고 다시 연결 경로를 반복하는 접근 방식이 작동하지 않습니다. 파이썬은 항상 캐시의 첫 번째 경로에서 클래스를로드합니다. 필자의 경우 모든 플러그인이 특정 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'이 (가)로드되지 않았습니다. 상대적 가져 오기를 수행 할 수 없습니다"라는 오류가 발생합니다. 따라서 이름을로드하기 전에 바인딩해야합니다. 그 이유는 상대 수입 시스템의 근본적인 불변입니다. ), 후자는 여기에 설명 된대로 전자의 foo 속성으로 표시되어야합니다 .


고마워요! 이 방법을 사용하면 하위 모듈 간의 상대적 가져 오기가 가능합니다. 큰!
tebanep

이 대답은 여기 설명서를 일치 : docs.python.org/3/library/...를 .
Tim Ludwinski

1
그러나 무엇 mymodule입니까?
Gulzar

@Gulzar, 그것은 당신이 나중에 할 수 있도록 모듈에 부여하고 싶은 이름입니다. "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터미널에서 excecute :

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

크레딧 / 소스 : saarrrr , 또 다른 스택 교환 질문


3
이 "임시"솔루션은 다른 곳에서 jupyter 노트북을 사용하여 프로젝트를 제작하려는 경우 훌륭한 답변입니다.
fordy

하지만 ... 경로를 변경하는 것은 위험합니다
Shai Alon

@ShaiAlon 경로를 추가하고 있으므로 한 컴퓨터에서 다른 컴퓨터로 코드를 전송하는 것 외에 다른 위험은 없습니다. 경로가 엉망이 될 수 있습니다. 따라서 패키지 개발을 위해 로컬 패키지 만 가져옵니다. 또한 패키지 이름은 고유해야합니다. 걱정이되면 임시 해결책을 사용하십시오.
Miladiouss 2014

28

구성 파일 (여러 부작용과 추가 합병증이 많이 있음)을 가져 오기를 원하지 않고 실행하기 만하면 결과 네임 스페이스에 액세스 할 수 있습니다. 표준 라이브러리는 runpy.run_path 형식으로 API를 제공합니다 .

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

이 인터페이스는 Python 2.7 및 Python 3.2 이상에서 사용할 수 있습니다


이 방법이 마음에 들지만 run_path의 결과를 얻을 때 액세스 할 수없는 사전이 있습니까?
Stephen Ellwood

"액세스 할 수 없음"은 무슨 뜻입니까? 당신은 (이 수입 스타일의 액세스가 실제로 필요하지 않습니다 만 좋은 옵션 이유의 것을)하지만, 내용이 일반 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 : config_file이라는 모듈이 없습니다"
Shai Alon

17

당신은 사용할 수 있습니다

load_source(module_name, path_to_file) 

imp 모듈의 메소드 .


... 그리고 imp.load_dynamic(module_name, path_to_file)DLL 을 위해
HEKTO

34
임프가 더 이상 사용되지 않습니다.
t1m0

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

더 많은 "최종"을 사용해야합니다. 예 :save_cwd = os.getcwd() try: … finally: os.chdir(save_cwd)
kay-SE는 악합니다.

11
@ChrisJohnson this is already addressed by the standard library예, 그러나 파이썬은 이전 버전과 호환되지 않는 나쁜 습관을 가지고 있습니다 ... 이 경우 즉시 버전을 확인하는 것보다 내 자신의 범용 함수를 작성하고 싶습니다. 그리고 예, 아마도이 코드는 너무 잘 보호되지는 않지만 더 나은 코드를 작성할 수있는 아이디어 (os.chdir ()입니다. 따라서 +1.
Sushi271

13

다음은 모든 Python 버전에서 작동하는 2.7-3.5 및 아마도 다른 코드입니다.

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

5
B / c sys.path [0] = xy는 첫 번째 경로 항목을 덮어 쓰지만 path [0 : 0] = xy는 path.insert (0, xy)와 같습니다.
dom0

2
hm path.insert가 나를 위해 일했지만 [0 : 0] 트릭은 효과가 없었습니다.
jsh

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

파이썬 모듈 test.py 만들기

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

파이썬 모듈 test_check.py 만들기

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

가져온 모듈을 모듈에서 가져올 수 있습니다.


4

파이썬 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

이것은 파이썬 3.4에서 사용되지 않는 모듈을 사용하는 것으로 보입니다. 이유를 이해하는 척하지 않지만 프로그램 내에서 작동하는 것 같습니다. Chris의 솔루션이 명령 줄에서 작동했지만 프로그램 내부에서는 작동하지 않는다는 것을 알았습니다.


4

나는 그것이 더 낫다고 말하지는 않지만, 완전성을 위해 exec파이썬 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

하루 종일 pyinstaller로 생성 된 exe에서 가져 오기 버그 문제를 해결했습니다. 결국 이것은 나를 위해 일한 유일한 것입니다. 이것을 만들어 주셔서 대단히 감사합니다!
frakman1

2

런타임에 패키지 모듈 가져 오기 (Python Recipe)

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내용을 변경하면 그것을 생성 하고 업데이트합니다./absolute/path/to/module/module.py

그런 다음 mypythonscript.py에 다음을 포함하십시오.

from module import *

1
이것은 내가 사용한 핵이며 몇 가지 문제를 일으켰습니다. 가장 고통스러운 것 중 하나는 IDEA에 링크 내에서 변경된 코드를 가져 오지 않지만 문제가있는 부분을 저장하려고하는 문제가 있다는 것입니다. 마지막으로 구해야 할 경쟁 조건은 무엇입니까? 나는 이로 인해 상당한 양의 작업을 잃었습니다.
Gripp

@Gripp는 귀하의 문제를 이해하고 있는지 확실하지 않지만 CyberDuck과 같은 클라이언트와 SFTP를 통해 데스크탑에서 원격 서버의 스크립트를 자주 (거의 독점적으로) 편집합니다. 심볼릭 링크 된 파일을 편집하는 대신 원본 파일을 편집하는 것이 훨씬 안전합니다. 스크립트의 변경 사항이 실제로 원본 문서로 돌아가서 에테르에서 손실되지 않는지 git확인하기 git status위해를 사용 하고 확인 하여 이러한 문제 중 일부를 파악할 수 있습니다 .
user5359531

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

파이썬에서 테스트 3.7.4, 3.2.5,2.7.16

찬성 :

  • 두 모듈을 하위 모듈로 가져올 수 있으며 모듈의 내용을 부모 모듈 (또는 부모 모듈이없는 경우 전역)로 가져올 수 있습니다.
  • 파일 이름에 마침표가있는 모듈을 가져올 수 있습니다.
  • 모든 확장 모듈에서 확장 모듈을 가져올 수 있습니다.
  • 기본적으로 확장자가없는 파일 이름 (예 testlib.std.py: testlib, testlib.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_module( tkl_declare_global함수를 통해) 가져 오는 모든 하위 모듈에 선언 된 위치에서 자동으로 내보낼 수 있습니다.

단점 :

  • [for 3.3.xand lower] (코드 복제) tkl_import_module를 호출하는 모든 모듈에서 선언해야 tkl_import_module

업데이트 1,2 ( 3.4.x이상) :

Python 3.4 이상에서는 최상위 모듈에서 선언 tkl_import_module하여 각 모듈에서 선언 해야하는 요구 사항을 무시할 수 tkl_import_module있으며 함수는 단일 호출 (모든 종류의 자체 배포 가져 오기)로 모든 하위 모듈에 자신을 주입합니다.

업데이트 3 :

가져 오기시 지원 실행 가드를 사용하여 tkl_source_modulebash에 아날로그로 기능 을 추가했습니다 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) 파이썬 모듈을 가져올 수 있습니다 :

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 3에서도 작동하지만 Python 2.7에서 테스트 됨) :

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()
Ataxias

0

이 답변은 Sebastian Rittau의 답변에 대한 답변입니다. "하지만 모듈 이름이 없으면 어떻게합니까?" 이것은 파일 이름이 주어진 파이썬 모듈 이름을 얻는 빠르고 더러운 방법입니다. __init__.py파일이 없는 디렉토리를 찾은 다음 파일 이름으로 다시 바꿀 때까지 트리로 올라갑니다 . 파이썬 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.