207

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

11 回答 11

235

从 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')
于 2009-02-13T22:02:57.683 回答
168

如果您不想自己动手,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)."""
于 2014-07-17T23:52:06.197 回答
154
import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
于 2013-10-07T14:55:19.610 回答
35

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

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

请记住,如果您要导入没有., likereargparseuse 的内容:

re = __import__('re')

以下是import_string.

于 2019-04-09T18:49:57.827 回答
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)
于 2011-11-24T09:49:03.757 回答
12

这是分享我在尝试解决此问题时发现__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
于 2019-04-27T04:25:57.867 回答
1

如果你碰巧已经有一个你想要的类的实例,你可以使用 '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()
于 2018-12-17T14:40:03.613 回答
0

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

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

那么,b 是类 'MyClass' 的一个实例

于 2017-06-16T15:13:56.350 回答
0

Python 有一个内置库 importlib 来完成这项工作。: , 如何绕过包名作为参数动态访问模块方法和类方法。下面给出一个例子。

模块一:

def get_scenario_data():
    return "module1 scenario data"


class Module1:

    def module1_function1(self):
        return "module1_function"

    def module1_function2(self):
        return "module2_function"

模块 2:

def get_scenario_data():
    return "module2 scenario data"



class Module2:

    def module2_function1(self):
        return "module2_function1"

    def module2_function2(self):
        return "module2_function2"

模块测试:

  1. 将根据包名作为参数动态访问模块方法
  2. 将根据包名作为参数动态访问类方法。

模块测试

import importlib

module = importlib.import_module('pack1.nestedpack1.module1')
print(module.get_scenario_data())
modul1_cls_obj = getattr(module, 'Module1')()
print(modul1_cls_obj.module1_function1())
print(modul1_cls_obj.module1_function2())

module = importlib.import_module('pack1.nestedpack1.module2')
modul2_cls_obj = getattr(module, 'Module2')()
print(modul2_cls_obj.module2_function1())
print(modul2_cls_obj.module2_function2())
print(module.get_scenario_data())

结果

module1 scenario data
module1_function
module2_function
module2_function1
module2_function2
module2 scenario data
于 2021-08-18T05:52:50.227 回答
-1

在 Google App Engine 中有一个webapp2名为import_string. 有关更多信息,请参见此处:https ://webapp-improved.appspot.com/api/webapp2.html

所以,

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

例如,这用于webapp2.Route您可以使用处理程序或字符串的地方。

于 2014-10-09T11:47:00.990 回答
-2
module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()
于 2009-02-13T22:01:44.067 回答