从名称实例化一个Python类

26

我有一组类和一个包含其中一个类名称的字符串。如何根据该字符串实例化一个类?

class foo:
  def __init__(self, left, right):
     self.left = left
     self.right = right

str = "foo"
x = Init(str, A, B)

我想让x成为类foo的一个实例。


2
重复。https://dev59.com/ikfRa4cB1Zd3GeqP6yuM,https://dev59.com/uXM_5IYBdhLWcg3w43pt,https://dev59.com/G3RB5IYBdhLWcg3wro6B等。 - S.Lott
6个回答

31
在你的情况下,你可以使用类似以下代码:
get_class = lambda x: globals()[x]
c = get_class("foo")

从模块中获取类甚至更加容易:

import somemodule
getattr(somemodule, "SomeClass")

20

如果你知道涉及的命名空间,你可以直接使用它。例如,如果所有类都在模块 zap 中,那么字典 vars(zap) 就是该命名空间; 如果它们都在当前模块中,globals() 可能是获取该字典最方便的方式。

如果这些类不都在同一命名空间中,则建立一个“人造”命名空间(一个专用字典,其中类名为键,类对象为值),就像 @Ignacio 建议的那样,可能是最简单的方法。


8
classdict = {'foo': foo}

x = classdict['foo'](A, B)

2
我如何使用反射来实现它? - klynch
1
可以使用getattr(),但这可能会让你面临安全问题。使用类装饰器将允许您自动枚举类,但这些仅存在于较新版本的Python中。 - Ignacio Vazquez-Abrams
你会如何使用装饰器?它是否会附加到可实例化类的列表中 - 我需要通过迭代该列表来选择正确的类来实例化吗? - Utkarsh Sinha
@UtkarshSinha:...不会,它会向classdict添加一个条目。 - Ignacio Vazquez-Abrams

6
classname = "Foo"
foo = vars()[classname](Bar, 0, 4)

Or perhaps

def mkinst(cls, *args, **kwargs):
    try:
        return globals()[cls](*args, **kwargs)
    except:
        raise NameError("Class %s is not defined" % cls)

x = mkinst("Foo", bar, 0, 4, disc="bust")
y = mkinst("Bar", foo, batman="robin")

关于这个代码片段的杂项注释:

*args**kwargs 是 Python 中的特殊参数,它们分别表示“非关键字参数数组”和“关键字参数字典”。

PEP-8(Python 官方风格指南)建议使用 cls 作为类变量。

vars() 返回本地范围内定义的变量的字典。

globals() 返回环境外部当前存在的变量的字典。


2

0
您可以考虑使用元类(metaclass):
Cls = type('foo', (), foo.__dict__)
x = Cls(A, B)

然而它创建了另一个类似的类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接