gpt4 book ai didi

python - 如何从基类动态创建派生类

转载 作者:IT老高 更新时间:2023-10-28 21:31:26 25 4
gpt4 key购买 nike

例如我有一个基类如下:

class BaseClass(object):
def __init__(self, classtype):
self._type = classtype

我从这个类派生了几个其他类,例如

class TestClass(BaseClass):
def __init__(self):
super(TestClass, self).__init__('Test')

class SpecialClass(BaseClass):
def __init__(self):
super(TestClass, self).__init__('Special')

有没有一种很好的 Pythonic 方法可以通过将新类放入我当前范围的函数调用来动态创建这些类,例如:

foo(BaseClass, "My")
a = MyClass()
...

因为会有评论和问题,为什么我需要这个:派生类都具有完全相同的内部结构,不同之处在于构造函数采用了许多以前未定义的参数。因此,例如,MyClass 采用关键字 a 而类 TestClass 的构造函数采用 b c

inst1 = MyClass(a=4)
inst2 = MyClass(a=5)
inst3 = TestClass(b=False, c = "test")

但他们不应该使用类的类型作为输入参数,比如

inst1 = BaseClass(classtype = "My", a=4)

我得到了这个工作,但更喜欢另一种方式,即动态创建的类对象。

最佳答案

这段代码允许您创建具有动态的新类名称和参数名称。__init__ 中的参数验证只是不允许未知参数,如果您需要其他验证,例如类型,或者它们是强制性的,只需添加逻辑那里:

class BaseClass(object):
def __init__(self, classtype):
self._type = classtype

def ClassFactory(name, argnames, BaseClass=BaseClass):
def __init__(self, **kwargs):
for key, value in kwargs.items():
# here, the argnames variable is the one passed to the
# ClassFactory call
if key not in argnames:
raise TypeError("Argument %s not valid for %s"
% (key, self.__class__.__name__))
setattr(self, key, value)
BaseClass.__init__(self, name[:-len("Class")])
newclass = type(name, (BaseClass,),{"__init__": __init__})
return newclass

这就是这样工作的,例如:

>>> SpecialClass = ClassFactory("SpecialClass", "a b c".split())
>>> s = SpecialClass(a=2)
>>> s.a
2
>>> s2 = SpecialClass(d=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __init__
TypeError: Argument d not valid for SpecialClass

我看到您要求在命名范围内插入动态名称 --现在,that 在 Python 中不被认为是一个好习惯——你要么有变量名称,在编码时已知,或数据 - 以及在运行时学习的名称比“变量”更多的是“数据” -

因此,您可以将您的类添加到字典中并从那里使用它们:

name = "SpecialClass"
classes = {}
classes[name] = ClassFactory(name, params)
instance = classes[name](...)

如果您的设计绝对需要将名称纳入范围,做同样的事情,但使用 globals() 返回的字典调用而不是任意字典:

name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)

(类工厂函数确实可以在调用者的全局范围内动态插入名称 - 但这是更糟糕的做法,并且在 Python 实现之间不兼容。这样做的方法是获取调用者的执行帧,通过sys._getframe(1) 并在其f_globals 属性中设置帧的全局字典中的类名。

更新,tl;dr: 这个答案已经很流行,但它仍然非常具体到问题主体。关于如何的一般答案“从基类动态创建派生类” 在 Python 中是对 type 的简单调用,传递新的类名、带有基类的元组和新类的 __dict__ 主体 - 像这样:

>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})

更新
任何需要这个的人也应该检查dill项目 - 它声称能够像 pickle 对普通对象所做的那样对类进行腌制和取消腌制,并且在我的一些测试中一直使用它。

关于python - 如何从基类动态创建派生类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15247075/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com