使用.format打印__str__中的单个列表对象(** self .__ dict__)

时间:2012-11-28 01:29:27

标签: python string function python-3.x string-formatting

我正在为游戏角色对象打印一个stat块。在上一个问题中,我演示了一种在__str__函数中使用的方式来显示对象数据,如下所示:

def __str__(self):
    if self.poisoned is True:
        status = "[POISONED]"
    else:
        status = ""
    self.status = status
    return ('NAME: {name} {status}\n' \
            'XP:   {xp}\n' \
            'HP:   {hit_points}\n' \
            'SP:   {spell_points}\n' \
            'STR:  {strength}\n' \
            'DEX:  {dexterity}\n' \
            'WEAPON: {weapon}\n' \
            'SPELL:  {spell}\n' \
            'ITEM:   {item}\n' \
            'AURA:   {aura}\n' \
            ).format(**self.__dict__)

我想解决的问题与WEAPON,SPELL,ITEM和AURA变量有关。这些项在Character对象中定义为单个项目列表:weapon=[],依此类推。使用上面的方法返回列表对象而不是它包含的对象而没有[]。我会看到一个空白的" "字符串或列表的包含对象(如果存在而不是[]

NAME: Bones 
XP:   0
HP:   100
SP:   100
STR:  14
DEX:  19
WEAPON:   []
SPELL:    []
ITEM:     []
AURA:     []

我尝试了多项实验,包括在定义{weapon}后用{current_weapon}替换current_weapon = weapon[0]引用,如果列表对象为空,则无效。这只是IndexError: list index out of range的错误。我可以在对象实例化时生成项目,但这不起作用,因为self.item有时会是一个空列表容器。

我可以使用" "个对象传播列表,但是然后必须将它们与替换项目混在一起并跟踪它,这看起来非常不优雅且可能很麻烦。

我似乎无法以优雅的方式围绕上面__str__返回的列表对象进行打印。我还在学习Python,并且想要相信有一个简单的添加,我可以附加到这个return字符串来执行此操作。

3 个答案:

答案 0 :(得分:2)

另一个选择是使用字符串格式化的功能来检查传入内容的属性,以及self是方法中的局部变量这一事实:

def __str__(self):
    status = '[POISONED]' if self.poisoned else ''
    weapon = self.weapon[0] if self.weapon else ''
    spell = self.spell[0] if self.spell else ''
    item = self.item[0] if self.item else ''
    aura = self.aura[0] if self.aura else ''
    return ('NAME: {self.name} {status}\n'
            'XP:   {self.xp}\n'
            'HP:   {self.hit_points}\n'
            'SP:   {self.spell_points}\n'
            'STR:  {self.strength}\n'
            'DEX:  {self.dexterity}\n'
            'WEAPON: {weapon}\n'
            'SPELL:  {spell}\n'
            'ITEM:   {item}\n'
            'AURA:   {aura}\n'
            ).format(**locals())

答案 1 :(得分:1)

您可以创建dict的本地副本,并在将其传递给格式之前修改所需的值:

def __str__(self):
    local_data = self.__dict__.copy()

    local_data['status'] = "[POISONED]" if self.poisoned else ""

    local_data['weapon'] = " " if not self.weapon else ','.join(self.weapon)

    return ('NAME: {name} {status}\n' \
            'XP:   {xp}\n' \
            'HP:   {hit_points}\n' \
            'SP:   {spell_points}\n' \
            'STR:  {strength}\n' \
            'DEX:  {dexterity}\n' \
            'WEAPON: {weapon}\n' \
            'SPELL:  {spell}\n' \
            'ITEM:   {item}\n' \
            'AURA:   {aura}\n' \
            ).format(**local_data)

最好这样做,而不是简单地修改格式的属性,就像使用self.status一样。现在你只是修改临时副本。

答案 2 :(得分:1)

你可以用一种简单的方式做到这一点,即使不是那么微不足道。您可以修改字符串格式以获取整个对象并利用属性的强大功能。这样做的好处是不会创建字典的副本,这对于大对象来说可能很昂贵。

我会给你一个应该接近你需要的例子:

class A(object):
    def __init__(self):
        # one full list and one empty one
        self.c = [1,2,3]
        self.d = []

    #these two preperties create a string versione when requeste
    c_str = property(lambda self: ", ".join(str(i) for i in self.c))
    d_str = property(lambda self: ", ".join(str(i) for i in self.d))

    def __str__(self):
        #you have to use the dotted version because properties are not visibles 
        # from the dict attribute
        string = "c = {0.c_str} \nd = {0.d_str}"
        return string.format(self)
a = A()
print str(a)
# c = 1, 2, 3 
# d = 

如果您正在编程某种类型的游戏属性可能是一个巨大的救生员,因为您可以使用它们来获取复杂的值作为属性而不是函数,创建更清洁的代码。它们允许您实现甚至检查值的插入,例如值是正的。

编辑:

为什么我使用0.c_str代替c_str?这是因为属性是特殊对象,只有在使用点表示法(self.c_str)访问它们时才会调用它们。它们不存在于__dict__对象中,因此您无法使用它。如果您尝试打印__dict__,您只会看到值 c d

这就是为什么我将格式函数传递给整个对象并访问其属性而不是将其传递给对象字典。

如果你不喜欢0.c_str符号,你可以用不同的方式来逃避它,例如保持它接近通常的符号:

"{self.c_str}".format(self=self)

"{foo.c_str}".format(foo=self)