Python:使用用户输入作为类名的类工厂

Posted

技术标签:

【中文标题】Python:使用用户输入作为类名的类工厂【英文标题】:Python: Class factory using user input as class names 【发布时间】:2011-01-28 12:55:38 【问题描述】:

我想动态地将类属性添加到超类。此外,我想创建从这个超类动态继承的类,这些子类的名称应该取决于用户输入。

有一个超类“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 的子类。

有什么想法吗?非常感谢! 再见 -佐野

【问题讨论】:

【参考方案1】:

要根据名称创建类,请使用class 语句并指定名称。观察:

def meta(name):
    class cls(Unit):
        pass

    cls.__name__ = name
    return cls

现在我想我应该解释一下自己,等等。当您使用 class 语句创建类时,它是动态完成的——相当于调用type()

例如下面两个sn-ps做同样的事情:

class X(object): pass
X = type("X", (object,), )

类的名称——类型的第一个参数——被分配给__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()

【讨论】:

谢谢德文!您和 Felix 的解决方案似乎都有一个我没有考虑过的副作用:新类是一个对象,需要与某些东西挂钩 - 存储在变量中或附加到列表或其他东西。我不能只创建 Knight 类,然后使用 myKnight = Knight() 调用构造函数。相反,我必须这样做: unitlist.append(meta("Knight")) myKnight = unitlist[0]() 有没有办法解决这个问题?说白了:将 Knight 类保存在代码中定义时保存 Unit 类的相同“一般位置”? @Sano98:我真的不确定你的意思。你可以先做Knight = meta("Knight"),然后再做myKnight = Knight()。你到底想要什么? 谢谢,这正是我想做的!只需将它保存在 Knight... 然后它在全局命名空间中,我可以像使用硬编码一样使用该类。太好了谢谢。只是没想到我可以在将课程保存为 Knight 时调用 Knight(),但是当然,为什么不呢? 回想起来,我想指出的是,Felix 给出“名称属性”的想法可能是正确的答案。【参考方案2】:

看看type() 内置函数。

knight_class = type('Knight', (Unit,), )
第一个参数:新类的名称 第二个参数:父类元组 第三个参数:类属性字典。

但在你的情况下,如果子类没有实现不同的行为,也许给 Unit 类一个 name 属性就足够了。

【讨论】:

我发现您的回答很有帮助。感谢您添加它,尽管其他人已经在那里!

以上是关于Python:使用用户输入作为类名的类工厂的主要内容,如果未能解决你的问题,请参考以下文章

设计模式1:简单工厂模式

如何使用类名在 Facebook 中输入用户名和密码

Python设计模式

如何在python子进程模块中执行用户输入(如日期)作为命令[重复]

Python 2.7 获取用户输入并作为不带引号的字符串进行操作

如何将用户输入作为按键,检测它,并使程序在Python中相应地运行?