首页 > 解决方案 > 作用于另一个类的多个实例的类函数

问题描述

我正在使用类构建一个简单的纸牌游戏,但遇到了一些令人困惑的事情。

首先是我的“Deck”类的相关方法。

class Deck(object):
    def __init__(self, starting_cards=[]):
        self._cards = starting_cards

    def get_amount(self):
        return len(self._cards)

    def add_card(self, card):
        self._cards.append(card)

这是我的“玩家”课程的一部分:

class Player(object):
    def __init__(self, name):
        self._name = name
        self._hand = Deck()
        self._coders = Deck()

    def get_hand(self):
        return self._hand

    def get_coders(self):
        return self._coders

    def has_won(self):
        if self._coders.get_amount() >= 4:
            return True
        else:
            return False

有一些“卡片”子类,但它们与这个问题无关,下面的代码应该向 self._hand 添加 3 张卡片,但它将卡片添加到 self._hand 和 self._coders,这是两个完全不同的Deck() 类的实例。

player = Player("Lochie Deakin-Sharpe")
player.get_hand().add_card(NumberCard(3))
player.get_hand().add_card(KeyboardKidnapperCard())
player.get_hand().add_card(AllNighterCard())
player.get_hand() 

我的代码的哪一部分将这些卡片添加到 self._coders 中,据我所知没有调用?

运行上面的代码后,这里有一些命令:

>>> player.get_coders()
Deck(NumberCard(3), KeyboardKidnapperCard(), AllNighterCard())

>>> player.get_hand().add_card(4)
>>> player.get_hand()
Deck(NumberCard(3), KeyboardKidnapperCard(), AllNighterCard(), 4)

>>> player.get_coders()
Deck(NumberCard(3), KeyboardKidnapperCard(), AllNighterCard(), 4)

标签: pythonpython-3.xclassoop

解决方案


看起来您的 Player 类有两个相同 _cards 列表的引用。

在 Python 中,您必须非常小心地将列表作为默认参数传递。要了解我的意思,请在定义类后运行以下代码:

p = Player('Me')
print('Memory Address of Hand: 0x{}'.format(id(p.get_hand()._cards)))
print('Memory Address of Coders: 0x{}'.format(id(p.get_coders()._cards)))

注意hand list和coder list的内存地址是一样的。这是因为将默认列表从参数直接传递到类属性的棘手行为。

要避免这种行为,请将以下位添加到您的 Deck初始化函数中:

def __init__(self, starting_cards=None):
    if starting_cards is None:
        starting_cards = []
    self._cards = starting_cards

我们将把starting_cards 设置为None,而不是直接从默认参数传递空列表。如果我们发现未传递起始卡片列表,则实例化一个空列表,然后将其分配给 _cards 属性。通过这样做,您可以避免对同一数组指针的多次引用。

这是一个常见的 Python 问题。如果您有兴趣了解更多关于它的信息,这篇文章很好地触及了这个概念:https ://docs.python-guide.org/writing/gotchas/

此外,Raymond Hettinger 就 Python 类开发的细微差别做了精彩的演讲。该视频来自 2013 年,但它仍然涵盖了在 Python 3 中制作 Pythonic 类所需的许多概念:https ://www.youtube.com/watch?v=HTLu2DFOdTg

例如,最好@property在 Python 类中使用而不是显式的 getter 和 setter,这有助于随着时间的推移提高类的性能和可读性。


推荐阅读