将字符串转换为 Python 类对象?

2025-02-12 10:03:00
admin
原创
73
摘要:问题描述:将字符串作为用户输入提供给 Python 函数,如果当前定义的命名空间中有一个同名的类,我想从中获取一个类对象。本质上,我想要一个函数的实现,它将产生这种结果:class Foo: pass str_to_class("Foo") ==> <class __...

问题描述:

将字符串作为用户输入提供给 Python 函数,如果当前定义的命名空间中有一个同名的类,我想从中获取一个类对象。本质上,我想要一个函数的实现,它将产生这种结果:

class Foo:
    pass

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

这是可能的吗?


解决方案 1:

这可能有效:

import sys

def str_to_class(classname):
    return getattr(sys.modules[__name__], classname)

解决方案 2:

警告eval()可用于执行任意 Python 代码。切勿其用于eval()不受信任的字符串。(请参阅Python 的 eval() 在不受信任的字符串上的安全性?

这看上去最简单。

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

解决方案 3:

你可以做类似的事情:

globals()[class_name]

解决方案 4:

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')

解决方案 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 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)

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

解决方案 7:

如果您确实想检索使用字符串创建的类,则应将它们存储(或正确措辞,引用)在字典中。毕竟,这还允许在更高级别命名您的类并避免暴露不需要的类。

例如,在一个游戏中,演员类别是用 Python 定义的,并且你想避免通过用户输入到达其他通用类别。

另一种方法(如下例所示)是创建一个全新的类,用于保存dict上述内容。这将:

  • 允许创建多个类别持有者以便于组织(例如,一个用于演员类别,另一个用于声音类型);

  • 使持有人和所举办的课程的修改变得更容易;

  • 并且您可以使用类方法将类添加到字典中。(尽管下面的抽象并不是真正必要的,但它仅仅是为了…… “说明”)。

例子:

class ClassHolder:
    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:
    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:
    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这样你就不会丢失你所做的所有课程:^)

更新:也可以使用装饰器作为简写。

class ClassHolder:
    def __init__(self):
        self.classes = {}

    def add_class(self, c):
        self.classes[c.__name__] = c

    # -- the decorator
    def held(self, c):
        self.add_class(c)

        # Decorators have to return the function/class passed (or a modified variant thereof), however I'd rather do this separately than retroactively change add_class, so.
        # "held" is more succint, anyway.
        return c 

    def __getitem__(self, n):
        return self.classes[n]

food_types = ClassHolder()

@food_types.held
class bacon:
    taste = "salty"

@food_types.held
class chocolate:
    taste = "sweet"

@food_types.held
class tee:
    taste = "bitter" # coffee, ftw ;)

@food_types.held
class lemon:
    taste = "sour"

print(food_types['bacon'].taste) # No manual add_class needed! :D

解决方案 8:

是的,你可以这样做。假设你的类存在于全局命名空间中,则类似下面的操作可以实现这一点:

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>

解决方案 9:

就任意代码执行或不必要的用户传递的名称而言,您可以有一个可接受的函数/类名称列表,如果输入与列表中的一个匹配,则对其进行评估。

附言:我知道......有点晚了......但这是为了将来偶然发现这个问题的人准备的。

解决方案 10:

对于我来说,使用importlib效果最好。

import importlib

importlib.import_module('accounting.views') 

这使用字符串点符号来表示您想要导入的 Python 模块。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2842  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1725  
  建设项目管理涉及众多环节与复杂流程,从规划设计到施工建设,再到竣工验收,每个阶段都需要高效的组织、协调与监控。随着数字化时代的到来,传统的项目管理方式面临诸多挑战,而数字化工具与平台的出现为建设项目管理带来了全新的思路与方法,极大地提升了管理效率与质量。在众多数字化工具与平台中做出合适的选择,成为建设项目管理者必须面对...
施工项目管理   1  
  建设项目管理是一个复杂且系统的工程,涉及众多环节与因素。成功的项目管理能够确保项目按时、按质量、在预算范围内交付,为相关方带来预期的收益。而在这一过程中,有五大关键成功因素起着决定性作用,它们相互关联、相互影响,共同构建起项目成功的基石。深入理解并有效运用这些因素,对于项目管理者而言至关重要。清晰的项目目标与规划明确清...
项目管理经验   1  
  在企业发展进程中,数字化转型已成为不可阻挡的趋势。它犹如一股强大的力量,推动着企业在复杂多变的市场环境中寻求新的突破与发展。而项目管理制度作为企业运营的重要支撑,在数字化转型的浪潮中扮演着举足轻重的角色。项目管理制度并非孤立存在,它与数字化转型紧密相连,相互影响、相互促进。有效的项目管理制度能够为数字化转型提供坚实的保...
工程项目管理的主要特征   1  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用