Динамически импортировать метод в файл, из строки - PullRequest
64 голосов
/ 09 января 2012

У меня есть строка, скажем: 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.

Ответы [ 9 ]

89 голосов
/ 09 января 2012

В 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()
28 голосов
/ 09 января 2012

Вам не нужно импортировать отдельные модули.Достаточно импортировать модуль, из которого вы хотите импортировать имя, и предоставить аргумент 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 модуля не дает никаких преимуществ.

20 голосов
/ 09 января 2012

Для Python <2.7 может использоваться встроенный метод <a href="http://docs.python.org/library/functions.html#__import__"> __ 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: </p>

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

Python> = 2.7:

mymethod = getattr(importlib.import_module("abc.def.ghi.jkl.myfile"), "mymethod")
7 голосов
/ 07 июня 2013

Неясно, что вы пытаетесь сделать со своим локальным пространством имен.Я предполагаю, что вы хотите просто 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()).Почему это сложная дискуссия.

4 голосов
/ 15 января 2018
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, "naemClassImportFromFile")

NClass = model() # Class From file 
1 голос
/ 10 ноября 2017

Этот сайт имеет хорошее решение: 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)
0 голосов
/ 01 февраля 2019

Как насчет этого:

def import_module(name):

    mod = __import__(name)
    for s in name.split('.')[1:]:
        mod = getattr(mod, s)
    return mod
0 голосов
/ 09 января 2012

Я склоняюсь к этому (как и ко многим другим библиотекам, таким как пилоны и вставки, если моя память мне правильно служит), чтобы отделить имя модуля от имени функции / атрибута, используя ': ' между ними. Смотрите следующий пример:

'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()
0 голосов
/ 09 января 2012

Использование importlib (только 2,7+).

...