通过"数据定义的覆盖来修改基类"

时间:2014-11-04 01:40:48

标签: python

不确定标题是否正确,但是当您不知道该怎么称呼它时,很难提出问题。

想象一下你有一类像

这样的东西
class Creature():
    def __init__( self ):
        self.str = 13
        self.dex = 10
        ...

此生物将获得影响它的其他定义。在这种情况下,想象一个生物对象被赋予了兽人的种族。 Orc会将它的str增加2.生物可以获得多个这些属性修改模板。

有没有办法组织代码,使这个优雅,pythonic,易于维护,并可能数据驱动?

2 个答案:

答案 0 :(得分:2)

首先,在没有使其成为数据驱动的情况下,如何做

class Orc(Creature):
    def __init__(self):
        super().__init__()
        self.str += 2
        self.race = 'Orc'

但是如果你想让它成为数据驱动怎么办?让我们假设数据只存储在一个表中,该表将种族名称映射到dicts,后者本身将属性名称映射为奖励。像这样:

races = {
    'Human': {},
    'Orc': {'str': +2, 'cha': -1},
    'Elf': {'str': -1, 'dex': +1, 'int': +1}
}

可以存储在JSON文件,SQLite数据库或任何您想要的内容中;它不必是源代码中嵌入的dict字面值。我只是这样做,以保持示例简单。

我们可以通过编程方式创建HumanOrcElf子类,但这可能没有充分的理由。我们真正需要的只是一个工厂函数,它创建了一个竞赛实例,之后它们都是相同的。所以:

def create_creature(race):
    bonuses = races.get(race, {})
    creature = Creature()
    for attr, bonus in bonuses.items():
        setattr(creature, attr, getattr(creature, attr) + bonus)
    creature.race = race
    return creature

这里唯一棘手的部分是setattr行。关键是我们在编写代码时不知道属性的名称,我们只在运行时知道它,但我们仍然希望能够获取或设置该值的值属性。通常,您不想使用setattrgetattr - 但是当您需要按名称动态访问属性时,这正是他们所依据的。

然而,值得注意的是还有另一种选择。您的代码中有多少实际上依赖于它们是Creature类的属性?他们可能只是一个字典的成员吗?

class Creature:
    def __init__(self):
        self.stats = {'str': 13, 
                      'dex': 10,
                      # ...
                     }

如果是这样,那么丑陋的setattr行变得更好了:

creature.stats[attr] += bonus

另一方面,程序中的其他一些代码可能会变得更加丑陋。也许不是这样:

if player.str + roll(20) > enemy.str + roll(20):

......你必须写:

if play.stats['str'] + roll(20) > enemy.stats['str'] + roll(20)

这种权衡几乎总是出现在数据驱动的对象中:程序的一部分希望将它们视为数据,另一部分希望将它们视为对象,并且必须平衡这两者。

答案 1 :(得分:1)

此处,Orc继承自Creature并将其str增加2:

class Creature():
    def __init__( self ):
        self.str = 13
        self.dex = 10

class Orc(Creature):
    def __init__( self ):
        Creature.__init__( self )
        self.str += 2

这是一个统治所有人的课程:

class Creature():
    d_str = {None:13, "Orc":15}
    d_dex = {None:10, "Orc":10}

    def __init__( self, race=None ):
        self.race = race
        self.str = self.d_str[race]
        self.dex = self.d_dex[race]