Как динамически загрузить класс Python


учитывая строку класса Python, например my_package.my_module.MyClass, каков наилучший способ загрузить его?

другими словами Я ищу эквивалент Class.forName() в Java, функция в Python. Он должен работать на Google App Engine.

предпочтительно это будет функция, которая принимает FQN класса в виде строки и возвращает ссылку на класс:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()
7 114

7 ответов:

из документации python, вот функция, которую вы хотите:

def my_import(name):
    components = name.split('.')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

причина простая __import__ не будет работать, потому что любой импорт чего-либо после первой точки в строке пакета является атрибутом импортируемого модуля. Таким образом, это не будет работать:

__import__('foo.bar.baz.qux')

вы должны были бы вызвать вышеуказанную функцию следующим образом:

my_import('foo.bar.baz.qux')

или в случае вашего примера:

klass = my_import('my_package.my_module.my_class')
some_object = klass()

EDIT: я был немного не в себе на этом. То, что вы в основном хотите сделать, это:

from my_package.my_module import my_class

эта функция нужна только если у вас есть пустой fromlist. Таким образом, соответствующий вызов будет выглядеть так:

mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')

если вы не хотите свернуть свой собственный, есть функция, доступная в pydoc модуль, который делает именно это:

from pydoc import locate
my_class = locate('my_package.my_module.MyClass')

преимущество этого подхода перед другими перечисленными здесь заключается в том, что locate найти любой объект python на предоставленном пунктирном пути, а не только объект непосредственно в модуле. например,my_package.my_module.MyClass.attr.

Если вам интересно, что их рецепт, вот эта функция:

def locate(path, forceload=0):
    """Locate an object by name or dotted path, importing as necessary."""
    parts = [part for part in split(path, '.') if part]
    module, n = None, 0
    while n < len(parts):
        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
        if nextmodule: module, n = nextmodule, n + 1
        else: break
    if module:
        object = module
    else:
        object = __builtin__
    for part in parts[n:]:
        try:
            object = getattr(object, part)
        except AttributeError:
            return None
    return object

он полагается на

import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
def import_class(cl):
    d = cl.rfind(".")
    classname = cl[d+1:len(cl)]
    m = __import__(cl[0:d], globals(), locals(), [classname])
    return getattr(m, classname)

хорошо, для меня это так и работает (я использую Python 2.7):

a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()

тогда b является экземпляром класса 'MyClass'

в Google App Engine есть

module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()