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

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

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

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

当前回答

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)

其他回答

为现有的答案增加了一点复杂性....

根据用例,显式指定你想导入的类/方法的完整路径(例如package.subpackage.module…)可能有点不方便。在importlib之上,我们可以利用__init__.py使事情更加简洁。

假设我有一个python包,像这样:

├── modes
│   ├── __init__.py
│   ├── bar.py
│   ├── foo.py
│   ├── modes.py

Foo.py,比如说,有一些类/函数,我们想在程序的其他地方使用:

from modes.modes import Mode

class Foo(Mode):
    def __init__(self, *arg, **kwargs):
        super(Foo, self).__init__(*arg, **kwargs)
        
    def run(self):
        self.LOG.info(f"This is FOO!")

使用命令行参数,我可以传递一个与我想要运行的模式对应的参数。我希望能够像这样

def set_mode(mode):
    """  """
    import importlib
    module = importlib.import_module('modes.foo')
    getattr(module, mode)().run()

输出:

>> set_mode("Foo")
>> engine_logger:INFO - This is FOO!

这很好,但是我们真正想要得到的是:

def set_mode(mode):
    """  """
    import importlib
    module = importlib.import_module('modes')  # only import the package, not modules explicitely
    getattr(module, mode)().run()

这会引发一个错误:

>> set_mode("Foo")
>> AttributeError: module 'modes' has no attribute 'Foo'

但是,我们可以在/modes/__init__.py中添加以下内容:

from .foo import Foo
from .bar import Bar

然后,我们可以做:

>> set_mode("Foo")
>> engine_logger:INFO - This is FOO!

>> set_mode("Bar")
>> engine_logger:INFO - This is BAR!

在其他情况下,我们在init.py中导入的所有子模块/函数/类都可以直接在importlib.import_module(…)中找到,而不必从外部指定完整的路径。

如果你使用的是Django,你可以使用import_string。

是的,我知道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')

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

re = __import__('re')

如果你碰巧已经有一个你想要的类的实例,你可以使用'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()
module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()

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

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

b是MyClass类的一个实例