在Python及其构造函数中动态创建类

时间:2014-03-24 00:12:07

标签: python inheritance lambda evaluation

我必须创建给定类的许多子类。我不想手动这样做(因为课程数量可能很大。我有一个几乎可行的解决方案......几乎 - 看看下面的例子,请告诉我我做错了什么。

ZOO_CLASSES字典为每个动物(字符串)保存(并且必须保持)我们创建的类。

最终解决方案必须使用Animal基类的继承,并且必须使用

创建每种动物物种的对象
one_lion = Lion()

one_lion = ZOO_CLASSES['Lion']()

我发现的问题是(因为测试会显示你是否运行它们 - 而不是“真,假,这是狮子,这是熊”我得到“真,真,这是鹦鹉,这是Parrot“。我认为问题在于,当调用构造函数并评估其参数(self和i)时,它需要最后指定的值(i =”Parrot“)。但是,我创建的对象属于正确的类类型而我没有看到任何其他意外行为。

顺便说一句,我是Python新手。 :)

class Animal:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return "This is " + self.name

    def __eq__(self, other):
        return self.name == other.name

ZOO = ['Lion', 'Bear', 'Parrot'] # list with many animals

ZOO_CLASSES = {}
for i in ZOO:
    ZOO_CLASSES[i] = type(i, (Animal,), dict(__init__=lambda self: Animal.__init__(self, i)))

# or even tried:
for i in ZOO:
    def constructor(self):
        Animal.__init__(self, i)
    ZOO_CLASSES[i] = type(i, (Animal,), dict(__init__=constructor))

# each time it creates a different function (as should be) but the value of i stays to the last one in the list:
# tests:
print(ZOO_CLASSES["Lion"]() == ZOO_CLASSES["Lion"]()) # True
print(ZOO_CLASSES["Lion"]() == ZOO_CLASSES["Bear"]()) # False
print(str(ZOO_CLASSES["Lion"]())) # This is Lion
print(str(ZOO_CLASSES["Bear"]())) # This is Bear
# i.e. all times we call these classes (their constructors) - i gets evaluated as "Parrot" (last element of ZOO list)

###################
# I don't want to do this (because imagine if the list ZOO is really long,
# manually typing it would be stupid):
class Lion(Animal):
    def __init__(self):
        Animal.__init__(self, "Lion")

class Bear(Animal):
    def __init__(self):
        Animal.__init__(self, "Bear")

class Parrot(Animal):
    def __init__(self):
        Animal.__init__(self, "Parrot")

1 个答案:

答案 0 :(得分:0)

问题是i中的lambda变量仅在您创建循环中定义的类的实例时才会被计算。此时循环将结束,i将设置为列表中的最后一项 - Parrot

您应该将i传递给lambda:

ZOO_CLASSES[i] = type(i, 
                      (Animal,), 
                      dict(__init__=lambda self, i=i: Animal.__init__(self, i)))
                                                 ^

演示:

>>> class Animal:
...     def __init__(self, name):
...         self.name = name
... 
>>> ZOO = ['Lion', 'Bear', 'Parrot']
>>> ZOO_CLASSES = {}

>>> for i in ZOO:
...     ZOO_CLASSES[i] = type(i, (Animal,), dict(__init__=lambda self: Animal.__init__(self, i)))
... 
>>> i
'Parrot'
>>> ZOO_CLASSES["Lion"]().name
'Parrot'

>>> for i in ZOO:
...     ZOO_CLASSES[i] = type(i, (Animal,), dict(__init__=lambda self, i=i: Animal.__init__(self, i)))
... 
>>> ZOO_CLASSES["Lion"]().name
'Lion'

另外,感谢@ BrenBarn的评论,请在此处查看更好的解释:Python lambda closure scoping

希望有所帮助。

相关问题