给定一个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()
从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')
在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
中使用,您可以使用处理程序或字符串。
如果你不想自己动手,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)."""
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)
如果你正在使用Django,你可以使用它。是的我知道OP没有要求django,但我遇到了这个问题,寻找一个Django解决方案,找不到一个,并把它放在这里寻找它的下一个男孩/ gal。
# 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')
好吧,对我来说这就是它的工作方式(我使用的是Python 2.7):
a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()
然后,b是类'MyClass'的实例
如果您碰巧已经拥有所需类的实例,则可以使用'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()
这是分享我在__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()