如何动态加载Python类
给定一个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()
Given a string of a Python class, e.g. my_package.my_module.MyClass
, what is the best possible way to load it?
In other words I am looking for a equivalent Class.forName()
in Java, function in Python. It needs to work on Google App Engine.
Preferably this would be a function that accepts the FQN of the class as a string, and returns a reference to the class:
my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
如果您不想自己动手,
pydoc
模块中提供了一个函数来完成此操作:与此处列出的其他方法相比,此方法的优点是
locate 将在提供的虚线路径中找到任何 python 对象,而不仅仅是直接在模块内的对象。 例如
my_package.my_module.MyClass.attr
。如果您好奇他们的配方是什么,请查看以下函数:
它依赖于 pydoc.safeimport 函数。 以下是相关文档:
If you don't want to roll your own, there is a function available in the
pydoc
module that does exactly this:The advantage of this approach over the others listed here is that
locate
will find any python object at the provided dotted path, not just an object directly within a module. e.g.my_package.my_module.MyClass.attr
.If you're curious what their recipe is, here's the function:
It relies on
pydoc.safeimport
function. Here are the docs for that:如果您使用的是 Django,则可以使用
导入字符串
。是的,我知道 OP 没有要求 django,但我在寻找 Django 解决方案时遇到了这个问题,但没有找到,并将其放在这里供下一个寻找它的男孩/女孩使用。
请记住,如果您想导入没有
.
的内容,例如re
或argparse
使用:If you're using Django you can use
import_string
.Yes i'm aware OP did not ask for django, but i ran across this question looking for a Django solution, didn't find one, and put it here for the next boy/gal that looks for it.
Keep in mind, if you want to import something that doesn't have a
.
, likere
orargparse
use:这里分享一下我在尝试解决这个问题时在 __import__ 和
importlib
上发现的一些东西。我正在使用Python 3.7.3。
当我尝试访问模块
abc
中的类d
时,mod
变量引用顶部命名空间a
。因此,为了到达
d
类,我需要:如果我们尝试这样做,
我们实际上是在尝试寻找
ad
。当使用
importlib
时,我想库已经为我们完成了递归getattr
。 因此,当我们使用 importlib.import_module 时,我们实际上获得了最深层模块的句柄。Here is to share something I found on
__import__
andimportlib
while trying to solve this problem.I am using Python 3.7.3.
When I try to get to the class
d
in modulea.b.c
,The
mod
variable refer to the top namespacea
.So to get to the class
d
, I need toIf we try to do
we are actually trying to look for
a.d
.When using
importlib
, I suppose the library has done the recursivegetattr
for us. So, when we useimportlib.import_module
, we actually get a handle on the deepest module.修复 python 3.11 上的错误导入
Fix error import on python 3.11
好的,对我来说,这就是它的工作方式(我使用的是 Python 2.7):
然后,b 是类“MyClass”的实例
OK, for me that is the way it worked (I am using Python 2.7):
Then, b is an instance of class 'MyClass'
如果您碰巧已经拥有所需类的实例,则可以使用“type”函数提取其类类型并使用它来构造一个新实例:
If you happen to already have an instance of your desired class, you can use the 'type' function to extract its class type and use this to construct a new instance:
Python 有一个内置库 importlib 来完成这项工作。 :,如何绕过包名称作为参数动态访问模块方法和类方法。 下面给出一个例子。
模块1:
模块2:
ModuleTest:
模块测试
结果
Python has an inbuilt library importlib to get the job done. :, How to access module method and class method dynamically bypassing package name as a param. An example is given below.
Module 1:
Module 2:
ModuleTest:
ModuleTest
Results
PyPI 模块自动加载器和 导入
测试:
PyPI module autoloader & import
Tests:
为现有答案添加一点复杂性......
根据用例,必须显式指定完整路径可能会有些不方便(例如
package.subpackage.module...
)您要导入的类/方法的名称。 在 importlib 之上,我们可以利用 __init__.py 使事情变得更加干净。假设我有一个 python 包,如下所示:
foo.py
,比如说,有一些我们想在程序中其他地方使用的类/函数:使用命令行参数,我可以传递与我想要运行的模式相对应的参数。 我希望能够做到这样的事情:
哪个输出:
工作正常,但是我们真正想要得到的是:
这会引发错误:
但是,我们可以将以下内容添加到
/ mode/__init__.py
:那么,我们可以这样做:
在其他世界中,我们在 init.py 中导入的所有子模块/函数/类都可以直接使用 importlib.import_module(...) 找到,而不必指定来自外部的完整路径。
Adding a bit of sophistication to the existing answers....
Depending on the use case, it may be somewhat inconvenient to have to explicitly specify the full path (E.g.
package.subpackage.module...
) of the class/method you want to import. On top of importlib, we can leverage__init__.py
to make things even cleaner.Let's say I have a python package, like so:
foo.py
, say, have some class/functions we'd like to use somewhere else in our program:With a command line argument, I can pass an argument that corresponds to a mode that I want to run. I'd like to be able to so something like this:
which outputs:
That works fine, however what we'd REALLY want to get at is this:
Which raises an error:
However, we can add the following to
/modes/__init__.py
:Then, we can do:
In other worlds, all sub modules/functions/classes we import in init.py will be found directly with importlib.import_module(...), without having to specify the full path from outside.
我已经创建了这个方法
现在,假设我们有以下文件夹结构和类:
如果我们执行导入函数:
输出:
I have created this method
Now, lets suppose we have the following folder structure and classes:
If we execute the import function:
Output:
大家可以试试这个:
One can try this:
在 Google App Engine 中,有一个名为
import_string
的webapp2
函数。 有关详细信息,请参阅此处:https://webapp-improved.appspot.com/api/webapp2 .html因此,
例如,这在
webapp2.Route
中使用,您可以在其中使用处理程序或字符串。In Google App Engine there is a
webapp2
function calledimport_string
. For more info see here:https://webapp-improved.appspot.com/api/webapp2.htmlSo,
For example this is used in the
webapp2.Route
where you can either use a handler or a string.从 python 文档中,这是您想要的函数:
简单的
__import__
不起作用的原因是因为包字符串中第一个点之后的任何导入都是您所在模块的属性输入。 因此,这样的东西是行不通的:你必须像这样调用上面的函数:
或者在你的例子中:
编辑:我对此有点偏离。 您基本上想要做的是:
仅当您有一个空 fromlist 时才需要上述函数。 因此,适当的调用将如下所示:
From the python documentation, here's the function you want:
The reason a simple
__import__
won't work is because any import of anything past the first dot in a package string is an attribute of the module you're importing. Thus, something like this won't work:You'd have to call the above function like so:
Or in the case of your example:
EDIT: I was a bit off on this. What you're basically wanting to do is this:
The above function is only necessary if you have a empty fromlist. Thus, the appropriate call would be like this: