在Python中动态创建类及其构造函数
我需要创建很多子类,都是从一个给定的类派生出来的。我不想手动去做这件事,因为类的数量可能会非常多。我有一个几乎可以工作的解决方案……差一点——看看下面的例子,帮我看看我哪里做错了。
ZOO_CLASSES这个字典里存放着每种动物(用字符串表示)对应的类。
最终的解决方案必须使用动物这个基类的继承,并且每种动物的对象必须通过
one_lion = Lion()
或者
one_lion = ZOO_CLASSES['Lion']()
来创建。
我发现的问题是(如果你运行测试就会看到——我得到的结果是“True, True, This is Parrot, This is Parrot”,而不是“True, False, This is Lion, This is Bear”)。我觉得问题出在调用构造函数并评估它的参数(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 个回答
1
问题在于,lambda
里面的i
变量只有在你创建类的实例时才会被计算。而这个时候,循环已经结束,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 闭包作用域。
希望这能帮到你。