不确定标题是否正确,但是当您不知道该怎么称呼它时,很难提出问题。
想象一下你有一类像
这样的东西class Creature():
def __init__( self ):
self.str = 13
self.dex = 10
...
此生物将获得影响它的其他定义。在这种情况下,想象一个生物对象被赋予了兽人的种族。 Orc会将它的str增加2.生物可以获得多个这些属性修改模板。
有没有办法组织代码,使这个优雅,pythonic,易于维护,并可能数据驱动?
答案 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
字面值。我只是这样做,以保持示例简单。
我们可以通过编程方式创建Human
,Orc
和Elf
子类,但这可能没有充分的理由。我们真正需要的只是一个工厂函数,它创建了一个竞赛实例,之后它们都是相同的。所以:
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
行。关键是我们在编写代码时不知道属性的名称,我们只在运行时知道它,但我们仍然希望能够获取或设置该值的值属性。通常,您不想使用setattr
和getattr
- 但是当您需要按名称动态访问属性时,这正是他们所依据的。
然而,值得注意的是还有另一种选择。您的代码中有多少实际上依赖于它们是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]