给定一个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()
给定一个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()
Answers:
在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
仅当您的发件人列表为空时,才需要上述功能。因此,适当的调用将如下所示:
mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')
如果您不想自己动手,则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)."""
qualname
(对象不在模块名称空间的顶部)。
locate('my_package.my_module.MyClass.attr.method.etc')
import importlib
module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
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)
(modulename, classname) = cl.rsplit('.', 2)
rsplit('.', 1)
?
如果您使用的是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')
请记住,如果您要导入不带.
,re
或的东西,请argparse
使用:
re = __import__('re')
这里是分享我在__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
module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()
在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
在可以使用处理程序或字符串的地方使用它。