如何动态加载Python类

时间:2009-02-13 21:49:05

标签: python reflection python-import

给定一个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()

10 个答案:

答案 0 :(得分:166)

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

答案 1 :(得分: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)."""

答案 2 :(得分:73)

import importlib

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

答案 3 :(得分: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)

答案 4 :(得分:5)

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

Service

请记住,如果要导入没有# 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') 的内容,例如.re,请使用:

argparse

答案 5 :(得分:1)

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

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

然后,b是“MyClass”类的实例

答案 6 :(得分: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()

答案 7 :(得分: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

答案 8 :(得分:-2)

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

答案 9 :(得分:-2)

在Google App Engine中有一个名为webapp2的{​​{1}}函数。有关详细信息,请参阅此处:https://webapp-improved.appspot.com/api/webapp2.html

所以,

import_string

例如,这可以在import webapp2 my_class = webapp2.import_string('my_package.my_module.MyClass') 中使用,您可以使用处理程序或字符串。