如何动态加载Python类

问题描述 投票:131回答:10

给定一个Python类的字符串,例如my_package.my_module.MyClass,加载它的最佳方法是什么?

换句话说,我在Java中寻找等效的Class.forName(),在Python中运行。它需要在Google App Engine上运行。

最好这是一个函数,它接受类的FQN作为字符串,并返回对类的引用:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()
python reflection python-import
10个回答
169
投票

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

编辑:我有点偏僻。你基本上想要做的是:

from my_package.my_module import my_class

仅当您有一个空的fromlist时,才需要上述功能。因此,适当的调用将是这样的:

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

-2
投票

在Google App Engine中有一个名为webapp2import_string函数。欲了解更多信息,请访问:https://webapp-improved.appspot.com/api/webapp2.html

所以,

import webapp2
my_class = webapp2.import_string('my_package.my_module.MyClass')

例如,这在webapp2.Route中使用,您可以使用处理程序或字符串。


102
投票

如果你不想自己动手,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

它依赖于pydoc.safeimport功能。以下是有关的文档:

"""Import a module; handle errors; return None if the module isn't found.

If the module *is* found but an exception occurs, it's wrapped in an
ErrorDuringImport exception and reraised.  Unlike __import__, if a
package path is specified, the module at the end of the path is returned,
not the package at the beginning.  If the optional 'forceload' argument
is 1, we reload the module from disk (unless it's a dynamic extension)."""

74
投票
import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()

29
投票
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)

6
投票

如果你正在使用Django,你可以使用它。是的我知道OP没有要求django,但我遇到了这个问题,寻找一个Django解决方案,找不到一个,并把它放在这里寻找它的下一个男孩/ gal。

# It's available for v1.7+
# https://github.com/django/django/blob/stable/1.7.x/django/utils/module_loading.py
from django.utils.module_loading import import_string

Klass = import_string('path.to.module.Klass')
func = import_string('path.to.module.func')
var = import_string('path.to.module.var')

请记住,如果你想导入没有.的东西,比如reargparse使用:

re = __import__('re')

1
投票

好吧,对我来说这就是它的工作方式(我使用的是Python 2.7):

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

然后,b是类'MyClass'的实例


0
投票

如果您碰巧已经拥有所需类的实例,则可以使用'type'函数来提取其类类型并使用它来构造新实例:

class Something(object):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(self.name)

one = Something("one")
one.display()
cls = type(one)
two = cls("two")
two.display()

0
投票

这是分享我在__import__importlib上找到的东西,同时试图解决这个问题。

我使用的是Python 3.7.3。

当我试图在模块d上课时a.b.c

mod = __import__('a.b.c')

mod变量引用顶部命名空间a

所以要上课d,我需要

mod = getattr(mod, 'b') #mod is now module b
mod = getattr(mod, 'c') #mod is now module c
mod = getattr(mod, 'd') #mod is now class d

如果我们尝试做

mod = __import__('a.b.c')
d = getattr(mod, 'd')

我们实际上是在寻找a.d

当使用importlib时,我想库已经为我们完成了递归getattr。因此,当我们使用importlib.import_module时,我们实际上可以处理最深层的模块。

mod = importlib.import_module('a.b.c') #mod is module c
d = getattr(mod, 'd') #this is a.b.c.d

-2
投票
module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()
© www.soinside.com 2019 - 2024. All rights reserved.