문자열에서 파일의 메서드를 동적으로 가져 오기


84

나는 문자열이 있습니다 abc.def.ghi.jkl.myfile.mymethod. 동적으로 가져 오려면 어떻게합니까 mymethod?

내가 어떻게했는지는 다음과 같습니다.

def get_method_from_file(full_path):
    if len(full_path) == 1:
        return map(__import__,[full_path[0]])[0]
    return getattr(get_method_from_file(full_path[:-1]),full_path[-1])


if __name__=='__main__':
    print get_method_from_file('abc.def.ghi.jkl.myfile.mymethod'.split('.'))

개별 모듈 가져 오기가 전혀 필요한지 궁금합니다.

편집 : Python 버전 2.6.5를 사용하고 있습니다.

답변:


111

Python 2.7에서는 importlib.import_module () 함수를 사용할 수 있습니다 . 다음 코드를 사용하여 모듈을 가져오고 그 안에 정의 된 객체에 액세스 할 수 있습니다.

from importlib import import_module

p, m = name.rsplit('.', 1)

mod = import_module(p)
met = getattr(mod, m)

met()

2
Python 문서는 importlib.import_module()over __import__(): docs.python.org/2/library/functions.html#__import__-2.7 이상을 사용하도록 권장 합니다.
BoltzmannBrain 2015

4
import_module + rsplit = 하나의 진정한 길.
Cecil Curry

32

개별 모듈을 가져올 필요가 없습니다. 이름을 가져 오려는 모듈을 가져오고 fromlist인수를 제공하면 충분합니다 .

def import_from(module, name):
    module = __import__(module, fromlist=[name])
    return getattr(module, name)

예를 abc.def.ghi.jkl.myfile.mymethod들어이 함수를 다음과 같이 호출하십시오.

import_from("abc.def.ghi.jkl.myfile", "mymethod")

(모듈 수준 함수는 메서드가 아니라 Python에서 함수라고합니다.)

이러한 간단한 작업의 경우 importlib모듈 을 사용하는 데 이점이 없습니다 .


import_from ()은 저를 올바른 방향으로 가리 켰습니다. myClass = getattr(__import__("module.to.import", fromlist=["myClassName"]), "myClassName"). 도와 주셔서 감사합니다!
Fydo

1
__import__접근 방식은 작업을 수행합니다. 하지만 help(__import__). "이 함수는 파이썬 인터프리터에서 사용하기위한 것이고 일반적인 사용을위한 것이 아니기 때문에 importlib.import_module()프로그래밍 방식으로 모듈을 가져 오는 데 사용하는 것이 좋습니다 ."라고 말합니다.
twasbrillig 2015

5
@twasbrillig :이 질문에 답했을 때 Python 2.5와 2.6이 여전히 널리 사용되었습니다. 오늘날에는 importlib대신 사용 하는 것이 가장 좋습니다.
스벤 Marnach

1
고마워요. 이를 반영하기 위해 답변을 업데이트하는 것이 좋습니다.
twasbrillig

26

Python <2.7의 경우 내장 메서드 __ import__를 사용할 수 있습니다.

__import__('abc.def.ghi.jkl.myfile.mymethod', fromlist=[''])

Python> = 2.7 또는 3.1의 경우 편리한 메소드 importlib.import_module 이 추가되었습니다. 다음과 같이 모듈을 가져옵니다.

importlib.import_module('abc.def.ghi.jkl.myfile.mymethod')

업데이트 : 주석에 따라 업데이트 된 버전 ( 끝까지 가져올 문자열을 읽지 않았고 모듈 자체가 아니라 모듈의 메서드를 가져와야한다는 사실을 놓 쳤음을 인정해야합니다) :

Python <2.7 :

mymethod = getattr(__import__("abc.def.ghi.jkl.myfile", fromlist=["mymethod"]))

Python> = 2.7 :

mymethod = getattr(importlib.import_module("abc.def.ghi.jkl.myfile"), "mymethod")

6
첫 번째 매개 변수가 및 둘 다에서 모듈 이름 이어야하므로 이러한 솔루션 중 어느 것도 작동하지 않습니다 . __import__()importlib.import_module()
Kris Hardy

1
importlib.import_module ( 'abc.def.ghi.jkl.myfile.mymethod')는 메서드의 "정규화 된"이름이 아니라 "절대 또는 상대 용어로 가져올 모듈"을 지정해야하기 때문에 작동하지 않습니다.
frm

가져올 첫 번째 매개 변수 는 문자열이 아닌 모듈이어야하므로 이는 분명히 작동하지 않습니다 .
Lakshman Prasad

11

로컬 네임 스페이스에 대해 수행하려는 작업이 명확하지 않습니다. 나는 당신이 my_method로컬로 원한다고 가정합니다 output = my_method().

# This is equivalent to "from a.b.myfile import my_method"
the_module = importlib.import_module("a.b.myfile")
same_module = __import__("a.b.myfile")
# import_module() and __input__() only return modules
my_method = getattr(the_module, "my_method")

# or, more concisely,
my_method = getattr(__import__("a.b.myfile"), "my_method")
output = my_method()

my_method로컬 네임 스페이스 에만 추가하는 동안 모듈 체인을로드합니다. sys.modules가져 오기 전과 후의 키를보고 변경 사항을 볼 수 있습니다 . 다른 답변보다 명확하고 정확하기를 바랍니다.

완전성을 위해 전체 체인을 추가하는 방법입니다.

# This is equivalent to "import a.b.myfile"
a = __import__("a.b.myfile")
also_a = importlib.import_module("a.b.myfile")
output = a.b.myfile.my_method()

# This is equivalent to "from a.b import myfile"
myfile = __import__("a.b.myfile", fromlist="a.b")
also_myfile = importlib.import_module("a.b.myfile", "a.b")
output = myfile.my_method()

마지막으로 __import__()프로그램 시작 후 검색 경로를 사용 하고 수정 한 경우 __import__(normal args, globals=globals(), locals=locals()). 그 이유는 복잡한 논의입니다.


의 첫 번째 예 the_modulesame_module잘못과 다른 결과를 생성합니다. 반대 투표.
sleepycal 2014-07-22

7
from importlib import import_module

name = "file.py".strip('.py')
# if Path like : "path/python/file.py" 
# use name.replaces("/",".")

imp = import_module(name)

# get Class From File.py
model = getattr(imp, "classNameImportFromFile")

NClass = model() # Class From file 

2
답해 주셔서 감사합니다. 한 가지 작은 문제입니다. .strip()말씀하신 경우 제대로 작동 하지 않는 것 같습니다 . 특히 파일이 "py"로 시작하면 해당 문자도 제거됩니다. 예를 들어, "pyfile.py".strip(".py")생산 "file"이 그것이 생성하는 것이 바람직 할 것이다 여기서, "pyfile"이 경우에. name.replace(".py","")그래도 잘 작동합니다.
jxmorris12

1

이 웹 사이트에는 좋은 해결책이 있습니다 : load_class . 다음과 같이 사용합니다.

foo = load_class(package.subpackage.FooClass)()
type(foo) # returns FooClass

요청한대로 웹 링크의 코드는 다음과 같습니다.

import importlib

def load_class(full_class_string):
    """
    dynamically load a class from a string
    """

    class_data = full_class_string.split(".")
    module_path = ".".join(class_data[:-1])
    class_str = class_data[-1]

    module = importlib.import_module(module_path)
    # Finally, we retrieve the Class
    return getattr(module, class_str)

주어진 링크의 요약 / 코드를 포함하십시오. 링크 전용 답변은 링크 부패가 발생하기 쉽기 때문에 좋지 않습니다.
Yet Another User


0

내가이 작업을 수행하는 방식 (내 메모리가 올바르게 작동하는 경우 pylon 및 붙여 넣기와 같은 여러 다른 라이브러리)은 ':'를 사용하여 모듈 이름을 함수 / 속성 이름에서 분리하는 것입니다. . 다음 예를 참조하십시오.

'abc.def.ghi.jkl.myfile:mymethod'

이렇게하면 import_from(path)아래 의 기능을 좀 더 쉽게 사용할 수 있습니다.

def import_from(path):
    """
    Import an attribute, function or class from a module.
    :attr path: A path descriptor in the form of 'pkg.module.submodule:attribute'
    :type path: str
    """
    path_parts = path.split(':')
    if len(path_parts) < 2:
        raise ImportError("path must be in the form of pkg.module.submodule:attribute")
    module = __import__(path_parts[0], fromlist=path_parts[1])
    return getattr(module, path_parts[1])


if __name__=='__main__':
    func = import_from('a.b.c.d.myfile:mymethod')
    func()

1
왜 anybdoy가 이것을해야합니까? 이를 위해서는 호출자가 모듈 이름과 속성 이름을 콜론으로 결합해야하며 함수는 콜론에서 다시 분할해야합니다. 처음에 두 개의 매개 변수를 사용하지 않는 이유는 무엇입니까?
Sven Marnach

1
종종 이것이 발생하는 상황은 구성 파일 (.yaml, .ini 등)을 사용하여 프레임 워크에서 애플리케이션으로 콜백을 연결하는 경우입니다. 그런 다음 구성 파일의 단일 문자열을 사용하여 프레임 워크가 호출해야하는 함수 등을 지정할 수 있습니다.
Kris Hardy

예, 이것을 구성 파일 구문으로 선택하는 것이 좋습니다. 그러나 이것이 OP의 질문과 어떤 관련이 있습니까? (내 설정 파일 구문으로 이것을 선택했습니다 경우에도, 나는 그렇지 임의 API 함수에 의해 내 config 파일 파서에 의해 구문 분석이 선호하는 것입니다.)
스벤 Marnach

-1

이것은 어떤가요 :

def import_module(name):

    mod = __import__(name)
    for s in name.split('.')[1:]:
        mod = getattr(mod, s)
    return mod

마법의 방법을 사용하는 것은 권장되지 않습니다. 대신 importlib를 사용하십시오.
dephinera

왜 낙담하는지 자세히 설명해 주시겠습니까? @dephinera
Aymen Alsaadi 2011

매직 메서드는 우리 코드가 아닌 인터프리터가 호출하기위한 것입니다. 명시 적으로 호출하면 서명이 변경되지 않지만 향후 언어 버전에서 변경 될 수 있습니다.
dephinera
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.