【问题标题】:Is there a way to create an object with dynamic parentage in python?有没有办法在 python 中创建具有动态父级的对象?
【发布时间】:2021-12-23 23:43:07
【问题描述】:

我想,最好的解释方式就是举例。编写游戏,为所有角色类创建一个父类,用于建立基本方法和价值观,以及一大群种族和职业的子类。

所以你有精灵、兽人、人类可以修改基本属性,然后是坦克、盗贼、施法者等可以进行额外修改的职业。通过使用 super(),做起来相当简单:

class ElfTank( Elf, Tank )

并获得您想要的组合修改。

有没有一种方法可以动态创建一个对象并指定其父对象,而无需创建九个预先确定的类(在三个职业和三个种族的情况下)?

注意:这是一个示例,因为我使用 PacMan 或 D&D 来解释任何 OOP 事物要容易得多。实际的应用程序涉及两到六位父母,并且会涉及太多背景故事。

编辑:好的,根据反馈,以及对一些附加链接的挖掘,以及我自己的一些修补,我将回答我自己的问题。

【问题讨论】:

  • 这能回答你的问题吗? Dynamic inheritance in Python
  • 鉴于多重继承变得多么脆弱,我现在告诉你这是一个糟糕的主意。使用组合(Elf 可能包含引用Tank 或其他类的属性.class_,并可能通过__getattr__ 动态重定向查找)和/或公共属性(可能对Race 类使用ABC这需要存在 Class 作为属性),而不是多重继承。如果您觉得您不仅想要多重继承,还想要 动态 多重继承,那么您几乎肯定会得到an XY problem
  • 考虑改用组合,查找实体组件系统。

标签: python


【解决方案1】:

这些解决方案在技术上是可行的。但是,请注意,它们都是非常糟糕的想法。

如果你不需要向构造函数传递任何参数:

def makeMeAClass( *parents ):
    class dynamicClass( *parents ):
        def __init__(self):
            super().__init__()
    return dynamicClass()   

如果你想传递一个参数给构造函数,你可以简单地把它 在开始列出父类之前。 (这适用于任意数量的参数,只要参数数量一致)。

def MakeMeAClassWithAnArgument( argument, *parents )
    class dynamicClass( *parents ):
        def __init__(self, argument):
             super().__init__(argument)
    return dynamicClass( argument )

如果你真的想发疯,你甚至可以将动态数量的参数传递给构造函数,但它们必须由关键字指定。

def MakeMeAClassWithDynamicArguments( *parents, **arguments )
    class dynamicClass( *parents ):
        def __init__(self, **arguments):
            super().__init__(**arguments)
    return dynamicClass(**arguments)

但是,有更好的方法可以做到这一点,特别是如果您最终会得到多个具有相同父系的对象 - 您最终会得到多个动态生成的完全相同的对象类,但需要内存中的多个位置,这在某种程度上抵消了 OOP 的许多好处。

在研究这种事情以接受“不要那样做”时,我遇到了足够多的阻力,我还没有真正深入研究原因。对于那些需要听到后续“不,真的,不要那样做”的人,我欢迎更有资格的 cmets。

【讨论】:

  • 和你这里的函数类似,Python 的type() 内置函数可以用来动态创建一个类。见google.com/amp/s/www.geeksforgeeks.org/python-type-function/amp
  • 虽然我完全同意可能有更好的方法,并且动态类生成可能不是您正在寻找的解决方案。 (不是 OP 中的你……阅读此评论的人中的你)。
  • 根本不需要覆盖__init__;如果您不覆盖它,并且所有父母都适当地使用super(),那么孩子将正确地从所有这些人那里继承(如果父母失败,让孩子明确实现__init__ 将不会解决任何问题 i> 适当地使用super(),只是为了清楚)。 class dynamicClass( *parents ): pass 可以更快地完成相同的工作,并且无需选择在真空中使用哪个 __init__ 签名。
猜你喜欢
  • 1970-01-01
  • 2020-02-05
  • 2022-10-12
  • 2018-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-31
  • 2022-01-08
相关资源
最近更新 更多