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

换句话说,我正在寻找一个等效的Class.forName()在Java,函数在Python。它需要工作在谷歌应用程序引擎。

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

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

当前回答

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

其他回答

下面是分享一些我在__import__和importlib上发现的东西,同时试图解决这个问题。

我使用的是Python 3.7.3。

当我在a.b.c模块中找到d类时,

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

我们其实是在找ad

在使用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

在谷歌应用引擎中有一个名为import_string的webapp2函数。更多信息请参见:https://webapp-improved.appspot.com/api/webapp2.html

So,

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

例如,这在webapp2中使用。可以使用处理程序或字符串的路由。

PyPI模块自动加载和导入

# PyPI imports
import pkg_resources, subprocess, sys

modules   = {'lxml.etree', 'pandas', 'screeninfo'}
required  = {m.split('.')[0] for m in modules}
installed = {pkg.key for pkg in pkg_resources.working_set}
missing   = required - installed

if missing:
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', '--upgrade', 'pip'])
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', *missing])

for module in set.union(required, modules):
    globals()[module] = __import__(module)

测试:

print(pandas.__version__)
print(lxml.etree.LXML_VERSION)

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

模块1:

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"

ModuleTest:

将根据包名作为参数动态访问模块方法 将基于包名作为参数动态访问类方法。

ModuleTest

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

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