将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所以你永远不会失去所有的类:^)