给定一个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类的字符串,例如my_package.my_module。MyClass,最好的加载方式是什么?
换句话说,我正在寻找一个等效的Class.forName()在Java,函数在Python。它需要工作在谷歌应用程序引擎。
最好是这样一个函数,它接受类的FQN作为字符串,并返回类的引用:
my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()
当前回答
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
其他回答
为现有的答案增加了一点复杂性....
根据用例,显式指定你想导入的类/方法的完整路径(例如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(…)中找到,而不必从外部指定完整的路径。
如果你碰巧已经有一个你想要的类的实例,你可以使用'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()
好的,对我来说,这就是它工作的方式(我使用Python 2.7):
a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()
b是MyClass类的一个实例
如果你使用的是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')
下面是分享一些我在__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