Python:使用用户输入作为类名的类工厂
我想动态地给一个父类添加属性。同时,我还想动态创建从这个父类继承的子类,而这些子类的名字应该根据用户输入来决定。
现在有一个父类叫“Unit”,我可以在运行时给它添加属性。这部分已经可以正常工作了。
def add_attr (cls, name, value):
setattr(cls, name, value)
class Unit(object):
pass
class Archer(Unit):
pass
myArcher = Archer()
add_attr(Unit, 'strength', 5)
print "Strenght ofmyarcher: " + str(myArcher.strength)
Unit.strength = 2
print "Strenght ofmyarcher: " + str(myArcher.strength)
这样就能得到想要的输出:
弓箭手的力量: 5
弓箭手的力量: 2
但是现在我不想提前定义子类“Archer”,而是想让用户来决定这个子类的名字。我尝试过类似的做法:
class Meta(type, subclassname):
def __new__(cls, subclassname, bases, dct):
return type.__new__(cls, subclassname, Unit, dct)
factory = Meta()
factory.__new__("Soldier")
但没有成功。我想我还没有真正理解new在这里的作用。 我想要的结果是
class Soldier(Unit):
pass
由工厂创建。如果我用“Knight”作为参数调用工厂,我希望能创建一个名为“Knight”的类,它是Unit的子类。
有什么想法吗?非常感谢!
再见
-Sano
2 个回答
看看这个type()
内置函数。
knight_class = type('Knight', (Unit,), {})
- 第一个参数:新类的名字
- 第二个参数:父类的元组
- 第三个参数:类属性的字典
不过在你的情况下,如果子类没有实现不同的行为,给Unit
类加一个name
属性就足够了。
要根据名字创建一个类,可以使用 class
这个语句,并给它一个名字。看下面的例子:
def meta(name):
class cls(Unit):
pass
cls.__name__ = name
return cls
现在我想解释一下我的意思。当你用 class 语句创建一个类时,这个过程是动态的——这就相当于调用 type()
。
比如,下面这两段代码做的是一样的事情:
class X(object): pass
X = type("X", (object,), {})
类的名字——也就是传给 type 的第一个参数——会被赋值给 __name__
,基本上就是这样了(__name__
这个值通常只在默认的 __repr__()
实现中用到)。如果你想用动态名字创建一个类,实际上可以这样调用 type,或者你也可以在之后直接修改类的名字。不过,使用 class
语法是有原因的——它很方便,而且后续添加和修改东西也简单。如果你想添加方法,比如说,代码会是:
class X(object):
def foo(self): print "foo"
def foo(self): print "foo"
X = type("X", (object,), {'foo':foo})
等等。所以我建议还是使用 class 语句——如果你一开始就知道可以这样做,你可能早就这么做了。直接使用 type
之类的会让事情变得很麻烦。
顺便说一下,不要手动调用 type.__new__()
,只用 type()
就可以了。