【问题标题】:Python: Child Inheriting Parents Default Values If Not SpecifiedPython:如果未指定,则子继承父默认值
【发布时间】:2014-02-25 19:38:05
【问题描述】:

相当中级程序员,但这里是 Python 初学者。我从事游戏已经有一段时间了,昨天我重组了我所有的课程。我最初只使用组合数据结构,现在我混合使用两者。当我想生成播放器时,我的问题就出现了。这是相关代码。

class Object(object):
    def __init__(self, **kwargs):
        DeaultValues={'x':0, 'y':0, 'name':None, 'texture':None, 'blocks':False, 'ObjectID':None, 'Fighter':None, 'Corpse':None, 'Skill':None, 'ai':None}
        for key,value in DeaultValues.items(): 
            try: 
                vars(self)[key] = kwargs[key]
            except ValueError: 
                vars(self)[key] = value
            except KeyError:
                vars(self)[key] = value
        self.x = kwargs['x']
        self.y = kwargs['y']
        self.name=kwargs['name']
        self.blocks=kwargs['blocks']
        self.ObjectID=self.AttachID()
        self.texture = kwargs['texture']

        #This section binds an actors compenents to itself
        self.Corpse = kwargs['Corpse']
        if self.Corpse:
            self.Corpse.owner = self
        self.Skill=kwargs['Skill']
        if self.Skill:
            self.Skill.owner = self
        self.Fighter = kwargs['Fighter']
        if self.Fighter:
            self.Fighter.owner = self
        self.ai = kwargs['ai']
        if self.ai:
            self.ai.owner = self

class HighActor(Object):
    def __init__(self, **kwargs):
        super(HighActor, self).__init__(**kwargs)

class Player(HighActor):
    def __init__(self, Level=1, Xp=0, PreviousLevel=0, PreviousLevelThreshold=100, LevelThreshold=500, **kwargs):
        super(Player, self).__init__(**kwargs)
        self.LevelThreshold = LevelThreshold
        self.PreviousLevelThreshold=PreviousLevelThreshold
        self.PreviousLevel=PreviousLevel
        self.Level = Level
        self.Xp = Xp

def SpawnPlayer():
    global player
    FighterComponent = Fighter(MaxHp=100, Hp=100, IsHasted=[False, False], death_function=None)
    CorpseComponent = Corpse()
    SkillComponent = HighActorSkill()
    player=Player(name="player", x=None, y=None, texture="player.png", blocks=True, ObjectID=None, Fighter=FighterComponent, Corpse=CorpseComponent, Skill=SkillComponent, ai=None)

上面的代码工作得很好,但它并没有真正继承任何东西。为了使播放器对象不出错,我必须添加以将基对象类的所有属性添加到播放器初始化中。如果我删除任何在 player=Player() 语句中设置为 none 的值,我会收到值错误或键错误。我试图通过一个默认值的字典来纠正这个问题,该字典遍历所有给定 init 的 kwargs,如果它们没有值,则将它们设置为找到的默认值。这一直有效,直到我得到任何组件。所以在没有指定ai=none的情况下,我得到了关键错误。我真的很希望我的代码采用这样的格式,如果我没有为任何基对象类属性指定值,则默认值将被传入,但如果我指定了一个值,则会传递给基类。我理想的最终结果是让我的玩家实例看起来像这样:

def SpawnPlayer():
    global player
    FighterComponent = Fighter(MaxHp=100, Hp=100, IsHasted=[False, False], death_function=None)
    CorpseComponent = Corpse()
    SkillComponent = HighActorSkill()
    player=Player(name="player", texture="player.png", blocks=True, Fighter=FighterComponent, Corpse=CorpseComponent, Skill=SkillComponent)

我怀疑我的继承不能 100% 工作,因为如果我遗漏了 ObjectID,即使应该分配它也会出错,因为在 Bass 类的 init 中它的集合等于 getid(self)。所以我要么是我的继承有问题(我真的在与 Super 斗争),要么是我的对象的签名,我不太确定我的问题是什么,更重要的是为什么。我不反对大幅更改代码签名,因为我仍在编写引擎,所以还没有任何东西依赖于此。应该怎么做?

【问题讨论】:

    标签: python-2.7 dictionary initialization multiple-inheritance super


    【解决方案1】:

    我认为你的班级结构应该不同。每个类应该只有它需要的属性,在你建立继承时添加新的,例如:

    class Object(object):
    
        def __init__(self, x=0, y=0, name=None, **kwargs):
            self.x = x
            self.y = y
            self.name = name
    
    
    class HighActor(Object):
    
        def __init__(self, corpse=None, skill=None, **kwargs):
            super(HighActor, self).__init__(**kwargs)
            self.corpse = corpse
            self.skill = skill
    
    
    class Player(HighActor):
    
        def __init__(self, level=1, xp=0, **kwargs):
            super(Player, self).__init__(**kwargs)
            self.level = level
            self.xp = xp
    

    在每个级别您指定属性 - 所有Objects 应该有xyname,所有HighActors 应该corpse 和@ 987654328@ 等。现在您可以指定参数以提供给层次结构的三个级别中的任何一个,或者将它们排除在外以获取默认值:

    player = Player(name="player one", skill=100, xp=12) 
    

    您可能有一些不适合此继承方案的东西 - 在您的模型中可以有多个单独的继承关系集,不要强求!


    之所以有效,是因为每个__init__ 末尾的**kwargs 将任何该方法不期望的关键字参数“清除”到字典kwargs 中,然后可以将它们全部传递到下一个级别。当你这样做时,super(...).__init__(**kwargs),这会将字典解压缩为关键字参数,任何不存在的都将采用指定的默认值。

    【讨论】:

    • 游戏中的大部分 Actor 都是基于 Object 基类构建的。我在这里省略了使这一点显而易见的类方法,但是 HighActor 包含很多方法,并且 HighActor 有一个额外的 Child 有区别。玩家类之所以存在,是因为它实际上是对象类的进一步特化。所有 Actor 都会死亡并使用能力,因此所有 Objects 都需要这些组件。我的代码完全符合 SoC。这甚至没有解决实际问题。
    • 所有Actors 可能都是Objects,但并非所有Objects 都必须是Actors。为什么不在ObjectHighActor 之间添加BaseActor?另外,如果你只给我看一点方案,我只能帮你一点点!
    • 基本actor与通用对象的区别在于它们成为所有者的组件。假设我想要游戏中的一个对象,它是一个间歇泉,每回合都会散发出毒云。我会将它初始化为一个没有战斗机或尸体组件的对象,但它会有一个技能组件来施放毒云能力。在这里使用组合结构是为了给我创建的对象提供很大的灵活性,允许对象和 Actor 的大量排列,而无需管理数量荒谬的类。
    • 您必须将属性移动到层次结构的适当部分,这很好。也许Objectskills 和Actor 添加corpsePlayer 添加fighter;你最有资格决定这一点。但是在我的回答中使用**kwargs 和默认参数会让你克服你遇到的问题。
    • 这行得通。提供有关父默认值与子指定值的解释的编辑会很棒,因为我还没有遇到有关其工作原理的具体解释。
    猜你喜欢
    • 2023-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 2014-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多