이름이 지정된 모듈을 문자열로 가져 오는 방법은 무엇입니까? 않고도 새 명령을 구현하는 새

예를 들어 인수로 명령으로 사용하는 Python 응용 프로그램을 작성 중입니다.

$ python myapp.py command1

응용 프로그램을 확장 가능하게, 즉 주 응용 프로그램 소스를 변경하지 않고도 새 명령을 구현하는 새 모듈을 추가 할 수 있기를 원합니다. 나무는 다음과 같습니다.

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

따라서 응용 프로그램이 런타임에 사용 가능한 명령 모듈을 찾아서 적절한 모듈을 실행하기를 원합니다.

파이썬은 __import__ 함수를 정의합니다.이 함수는 모듈 이름에 문자열을 사용합니다.

__import __ (이름, 전역 = 없음, 지역 주민 = 없음, 보낸 사람 목록 = (), 수준 = 0)

이 함수는 모듈 이름을 가져오고 주어진 전역 및 지역을 사용하여 패키지 컨텍스트에서 이름을 해석하는 방법을 결정합니다. fromlist는 이름으로 지정된 모듈에서 가져와야하는 오브젝트 또는 서브 모듈의 이름을 제공합니다.

출처 : 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()

이것은 잘 작동합니다.이 코드로 수행하는 작업을 수행하는 더 관용적 인 방법이 있는지 궁금합니다.

계란이나 확장 점을 사용하고 싶지는 않습니다. 이것은 오픈 소스 프로젝트가 아니며 “플러그인”이있을 것으로 기대하지 않습니다. 요점은 주 응용 프로그램 코드를 단순화하고 새 명령 모듈이 추가 될 때마다 코드를 수정할 필요가 없다는 것입니다.



답변

2.7 / 3.1보다 오래된 Python에서는 그렇게하는 것이 거의 같습니다.

최신 버전 importlib.import_modulePython 2Python 3을 참조하십시오 .

원한다면 사용할 수도 있습니다 exec.

또는 다음을 수행하여 __import__모듈 목록을 가져올 수 있습니다.

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

Dive Into Python 에서 직접 추출했습니다 .


답변

Python 2.7 및 3.1 이상에 권장되는 방법은 importlib모듈 을 사용하는 것입니다 .

importlib.import_module (이름, 패키지 = 없음)

모듈을 가져옵니다. name 인수는 절대 또는 상대 용어로 가져올 모듈을 지정합니다 (예 : pkg.mod 또는 ..mod). 이름이 상대적인 용어로 지정된 경우 패키지 인수는 패키지 이름을 해결하기위한 앵커 역할을하는 패키지 이름으로 설정해야합니다 (예 : import_module ( ‘.. mod’, ‘pkg.subpkg’) pkg.mod를 가져옵니다).

예 :

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

답변

참고 : 임프 는 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

답변

사용 꼬마 도깨비 모듈 , 또는 더 직접적인 __import__()기능을.


답변

요즘에는 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)

당신은 회원 (예를 들어이 기능 “에 액세스 할 수 있습니다이 방법 hello“) 모듈에서 pluginX.py이 코드에서 호출되는 – module– 네임 스페이스 아래를; 예, module.hello().

멤버 (예 : ” hello“) 를 가져 오려면 메모리 내 모듈 목록에 module/ pluginX를 포함시킬 수 있습니다 .

sys.modules[module_name] = module

from pluginX import hello
hello()

패키지 가져 오기

(패키지 가져 오기 예를 들어 , pluginX/__init__.py현재 디렉토리 아래의 것은) 사실 간단하다 :

import importlib

pkg = importlib.import_module('pluginX')

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

답변

현지인이 원하는 경우 :

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


답변

당신은 사용할 수 있습니다 exec:

exec("import myapp.commands.%s" % command)