问题:将字符串转换为Python类对象?
给定一个字符串作为Python函数的用户输入,如果当前定义的命名空间中有一个具有该名称的类,我想从中获取一个类对象。本质上,我想要一个函数的实现,该函数将产生这种结果:
class Foo:
pass
str_to_class("Foo")
==> <class __main__.Foo at 0x69ba0>
这是可能吗?
回答 0
警告:
eval()
可用于执行任意Python代码。您永远不要使用eval()
不受信任的字符串。(请参阅关于不可信字符串的Python eval()的安全性?)
这似乎最简单。
>>> class Foo(object):
... pass
...
>>> eval("Foo")
<class '__main__.Foo'>
回答 1
这可以工作:
import sys
def str_to_class(classname):
return getattr(sys.modules[__name__], classname)
回答 2
您可以执行以下操作:
globals()[class_name]
回答 3
您需要类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')
回答 4
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)
这样可以准确地处理旧样式和新样式的类。
回答 5
我看过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")
回答 6
是的,您可以这样做。假设您的类存在于全局命名空间中,则将执行以下操作:
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>
回答 7
就任意代码执行或不希望的用户传递名称而言,您可以具有可接受的函数/类名称的列表,如果输入与列表中的一个匹配,则进行评估。
PS:我知道。。。有点迟了。。。。。
回答 8
使用importlib最适合我。
import importlib
importlib.import_module('accounting.views')
这对您要导入的python模块使用字符串点表示法。
回答 9
如果您确实想检索使用字符串创建的类,则应存储(或措辞正确的引用)它们)在字典中。毕竟,这还将允许在更高级别上命名您的类,并避免暴露不需要的类。
例如,在一个游戏中,用Python定义了actor类,并且您希望避免用户输入会到达其他常规类。
另一种方法(如下面的示例所示)将创建一个包含dict
上述内容的全新类。这个会:
- 允许安排多个Class持有人以简化组织(例如,一个用于演员班,另一个用于声音类型);
- 使持有人和持有的Class的修改更加容易;
- 您可以使用类方法将类添加到dict。(尽管下面的抽象并不是真正必需的,它仅用于… “说明”)。
例:
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 a.a
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
这样您就不会丢失所做的所有类:^)