从类列表中创建实例

时间:2017-12-30 21:21:34

标签: python-3.x

如何从类列表中创建类的实例?我看过其他SO答案,但确实理解了它们。

我有一个班级列表:

list_of_classes = [Class1, Class2]

现在我想创建这些类的实例,其中存储类的变量名是类的名称。我试过了:

for cls in list_of_classes:
    str(cls) = cls()

但得到错误:“SyntaxError:无法分配给函数调用”。这当然是显而易见的,但我不知道该怎么做。

我真的希望以后能够按名称访问该类。假设我们将所有实例存储在一个dict中,并且其中一个类称为ClassA,那么我希望以后可以通过dict ['ClassA']访问该实例。那可能吗?还有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

你说你想要“存储类的变量名称[是]类的名称”,但这是一个非常糟糕的主意。变量名称不是数据。这些名称供程序员使用,因此很少有充分的理由使用代码生成它们。

相反,您应该填充实例列表,或者如果您确定要按类名索引,请使用字典映射名称到实例。

我建议像:

list_of_instances = [cls() for cls in list_of_classes]

或者这个:

class_name_to_instance_mapping = {cls.__name__: cls() for cls in list_of_classes}

有时候自动生成变量有意义的罕见情况之一是当您编写代码来自己创建或操作类对象时(例如自动生成方法)。这比创建全局变量更容易且更少,因为至少以编程方式生成的名称将包含在类名称空间中,而不是污染全局名称空间。

标准库中的collections.NamedTuple类工厂,例如,根据需要创建tuple子类,使用特殊描述符作为允许按名称访问元组值的属性。这是一个非常粗略的例子,说明如何使用getattrsetattr来动态操作属性,从而可以做一些模糊相似的事情:

def my_named_tuple(attribute_names):
    class Tup:
        def __init__(self, *args):
            if len(args) != len(attribute_names):
                raise ValueError("Wrong number of arguments")
            for name, value in zip(attribute_names, args):
                setattr(self, name, value)   # this programmatically sets attributes by name!

        def __iter__(self):
            for name in attribute_names:
                yield getattr(self, name)        # you can look up attributes by name too

        def __getitem__(self, index):
            name = attribute_names[index]
            if isinstance(index, slice):
                return tuple(getattr(self, n) for n in name)
            return getattr(self, name)
    return Tup

它的工作原理如下:

>>> T = my_named_tuple(['foo', 'bar'])
>>> i = T(1, 2)
>>> i.foo
1
>>> i.bar
2

答案 1 :(得分:0)

如果我确实理解了你的问题,我认为你可以使用globals()做这样的事情:

class A:
    pass

class B:
    pass

class C:
    pass

def create_new_instances(classes):
    for cls in classes:
        name = '{}__'.format(cls.__name__)
        obj = cls()
        obj.__class__.__name__ = name
        globals()[name] = obj

if __name__ == '__main__':
    classes = [A, B, C]
    create_new_instances(classes)
    classes_new = [globals()[k] for k in globals() if k.endswith('__') and not k.startswith('__')]
    for cls in classes_new:
        print(cls.__class__.__name__, repr(cls))

输出(您将获得类似的输出):

A__ <__main__.A object at 0x7f7fac6905c0>
C__ <__main__.C object at 0x7f7fac6906a0>
B__ <__main__.B object at 0x7f7fac690630>