将string转换为Python类对象?
给定一个string作为python函数的用户input,如果在当前定义的名称空间中有一个具有该名称的类,我希望从中获得一个类对象。 本质上,我想实现一个将产生这种结果的函数:
class Foo: pass str_to_class("Foo") ==> <class __main__.Foo at 0x69ba0>
这可能吗?
这似乎最简单。
>>> class Foo(object): ... pass ... >>> eval("Foo") <class '__main__.Foo'>
这可以工作:
import sys def str_to_class(str): return getattr(sys.modules[__name__], str)
你可以做这样的事情:
globals()[class_name]
你想要“Baz”类,它位于模块“foo.bar”中。 使用python 2.7,你想使用importlib.import_module(),因为这将使转换到python 3更容易:
import importlib def class_for_name(module_name, class_name): # load the module, will raise ImportError if module cannot be loaded m = importlib.import_module(module_name) # get the class, will raise AttributeError if class cannot be found c = getattr(m, class_name) return c
用python <2.7:
def class_for_name(module_name, class_name): # load the module, will raise ImportError if module cannot be loaded m = __import__(module_name, globals(), locals(), class_name) # get the class, will raise AttributeError if class cannot be found c = getattr(m, class_name) return c
使用:
loaded_class = class_for_name('foo.bar', 'Baz')
import sys import types def str_to_class(field): try: identifier = getattr(sys.modules[__name__], field) except AttributeError: raise NameError("%s doesn't exist." % field) if isinstance(identifier, (types.ClassType, types.TypeType)): return identifier raise TypeError("%s is not a class." % field)
这准确地处理旧式和新式的课程。
我已经看过如何Django处理这个
django.utils.module_loading有这个
def import_string(dotted_path): """ Import a dotted module path and return the attribute/class designated by the last name in the path. Raise ImportError if the import failed. """ try: module_path, class_name = dotted_path.rsplit('.', 1) except ValueError: msg = "%s doesn't look like a module path" % dotted_path six.reraise(ImportError, ImportError(msg), sys.exc_info()[2]) module = import_module(module_path) try: return getattr(module, class_name) except AttributeError: msg = 'Module "%s" does not define a "%s" attribute/class' % ( module_path, class_name) six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
你可以像import_string("module_path.to.all.the.way.to.your_class")
一样使用它import_string("module_path.to.all.the.way.to.your_class")
是的,你可以做到这一点。 假设你的类存在于全局命名空间中,像这样的事情会做到这一点:
import types class Foo: pass def str_to_class(s): if s in globals() and isinstance(globals()[s], types.ClassType): return globals()[s] return None str_to_class('Foo') ==> <class __main__.Foo at 0x340808cc>
在任意代码执行方面,或不需要的用户传递名称,您可以有一个可接受的函数/类名称的列表,如果input与列表中的一个匹配,则会被评估。
PS:我知道……有点晚了……但是对于任何人在未来绊倒了这一点。
使用importlib对我来说是最好的。
import importlib importlib.import_module('accounting.views')
这使用您想要导入的python模块的string点符号 。
如果你真的想要检索你使用string的类,你应该把它们存储在一个字典中(或者措辞恰当, 引用 )。 毕竟,这也将允许在更高层次上命名你的类,并避免暴露不需要的类。
例如,从一个游戏中,在Python中定义了actor类,并且要避免用户input到达其他常规类。
另一种方法(如下面的例子)将会形成一个全新的课程,上面写着这个dict
。 这个会:
- 允许多个class级人员组织起来,比如更容易组织(比如,一个演员class,另一个演出class)。
- 对持有者和正在举办的课程进行修改,
- 你可以使用类方法添加类到字典。 (虽然下面的抽象并不是真的有必要,但它仅仅是为了“插图” )。
例:
class ClassHolder(object): def __init__(self): self.classes = {} def add_class(self, c): self.classes[c.__name__] = c def __getitem__(self, n): return self.classes[n] class Foo(object): def __init__(self): self.a = 0 def bar(self): return self.a + 1 class Spam(Foo): def __init__(self): self.a = 2 def bar(self): return self.a + 4 class SomethingDifferent(object): def __init__(self): self.a = "Hello" def add_world(self): self.a += " World" def add_word(self, w): self.a += " " + w def finish(self): self.a += "!" return self.a aclasses = ClassHolder() dclasses = ClassHolder() aclasses.add_class(Foo) aclasses.add_class(Spam) dclasses.add_class(SomethingDifferent) print aclasses print dclasses print "=======" print "o" print aclasses["Foo"] print aclasses["Spam"] print "o" print dclasses["SomethingDifferent"] print "=======" g = dclasses["SomethingDifferent"]() g.add_world() print g.finish() print "=======" s = [] s.append(aclasses["Foo"]()) s.append(aclasses["Spam"]()) for a in s: print aa print a.bar() print "--" print "Done experiment!"
这返回给我:
<__main__.ClassHolder object at 0x02D9EEF0> <__main__.ClassHolder object at 0x02D9EF30> ======= o <class '__main__.Foo'> <class '__main__.Spam'> o <class '__main__.SomethingDifferent'> ======= Hello World! ======= 0 1 -- 2 6 -- Done experiment!
另一个有趣的实验就是添加一个方法来腌制ClassHolder
所以你永远不会失去所有的类:^)