Как динамически загрузить класс 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 ответов:
из документации 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)