给定一个字符串作为Python函数的用户输入,如果当前定义的命名空间中有一个具有该名称的类,则希望从中获得一个类对象。本质上,我想实现一个函数,它将产生这样的结果:

class Foo:
    pass

str_to_class("Foo")
==> <class __main__.Foo at 0x69ba0>

这有可能吗?


当前回答

你可以这样做:

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

Use:

loaded_class = class_for_name('foo.bar', 'Baz')

你可以这样做:

globals()[class_name]
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)

这可以准确地处理旧样式和新样式的类。

警告:eval()可用于执行任意Python代码。永远不要对不受信任的字符串使用eval()。(请参阅Python的eval()对不受信任字符串的安全性?)

这似乎是最简单的。

>>> class Foo(object):
...     pass
... 
>>> eval("Foo")
<class '__main__.Foo'>

我看了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")一样使用它。