prosource

모듈 이름을 문자열로 지정하여 동적으로 가져오려면 어떻게 해야 합니까?

probook 2023. 5. 8. 22:20
반응형

모듈 이름을 문자열로 지정하여 동적으로 가져오려면 어떻게 해야 합니까?

저는 명령을 인수로 사용하는 파이썬 애플리케이션을 작성하고 있습니다. 예를 들면 다음과 같습니다.

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

이 기능은 모듈을 가져옵니다.name잠재적으로 주어진 것을 사용하는globals그리고.locals패키지 컨텍스트에서 이름을 해석하는 방법을 결정합니다.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()

이것은 잘 작동합니다. 이 코드로 우리가 하고 있는 것을 달성할 수 있는 좀 더 관용적인 방법이 있는지 궁금합니다.

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


참고 항목: 전체 경로가 지정된 모듈을 가져오려면 어떻게 해야 합니까?

2.7/3.1 이전 버전의 Python에서는 거의 그렇게 할 수 있습니다.

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

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

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

파이썬으로 다이빙에서 바로 찢어졌습니다.

Python 2.7 및 3.1 이상에서는 모듈을 사용하는 것이 좋습니다.

importlib.import_module(name, package=None)

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

예.

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

참고: importlib을 선호하여 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

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)

# Verify contents of the module:
print(dir(module))

서부터여.module는 를나는모될것다니입객체를 모듈 가 될 것입니다.pluginX ("Module" ("Module")에한 것)pluginX를 으로써.import pluginX). 따라서, 예를 들어 a라고 부릅니다.hello함수는 매정된(파라미터 없음)에 .pluginX,사용하다module.hello().

가져오기"하려면 "" 기능을 사용해야 .from한 후 하는 "Memory"를 수행합니다.from가져오기:

sys.modules[module_name] = module

from pluginX import hello
hello()

패키지 가져오기

대신패를가면려져오호출, 키지출▁calling로 전화하기import_module충분합니다.패키지 폴더가 있다고 가정합니다.pluginX에서 작업을 수행한 그냥 합니다.

import importlib

pkg = importlib.import_module('pluginX')

# check if it's all there..
print(dir(pkg))

imp 모듈 또는 보다 직접적인 기능을 사용합니다.

다음을 사용할 수 있습니다.

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

현지인들이 원하는 경우:

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

@dumput의 솔루션과 유사하지만 재사용 가능하고 오류 허용성이 있는 솔루션은 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

다음 작품이 저에게 효과가 있었습니다.

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

다음은 저에게 효과가 있었습니다.

import sys, glob
sys.path.append('/home/marc/python/importtest/modus')
fl = glob.glob('modus/*.py')
modulist = []
adapters=[]
for i in range(len(fl)):
    fl[i] = fl[i].split('/')[1]
    fl[i] = fl[i][0:(len(fl[i])-3)]
    modulist.append(getattr(__import__(fl[i]),fl[i]))
    adapters.append(modulist[i]())

'modus' 폴더에서 모듈을 로드합니다.모듈에는 모듈 이름과 동일한 이름을 가진 단일 클래스가 있습니다.예: modus/modu1.py 파일에는 다음이 포함됩니다.

class modu1():
    def __init__(self):
        self.x=1
        print self.x

결과는 동적으로 로드된 클래스 "어댑터" 목록입니다.

언급URL : https://stackoverflow.com/questions/301134/how-can-i-import-a-module-dynamically-given-its-name-as-string

반응형