Class 属性定义为另一个列表类型的长度 class 属性不会自行更新并且总是 returns 相同的值

Class attribute defined as a length of another List Type class attribute doesn't update itself and always returns the same value

我正在为纸牌游戏编写代码 'War'。在定义“Deck”class 时,我定义了一个属性“self.cards”,它给出了一副纸牌中当前所有纸牌的列表。我还定义了一个属性“self.length”,它应该给出“self.cards”属性的长度。

但是,当我使用 表达式 deck.length 时,它 returns 一个固定值 ,即使牌组中的牌也不会改变("self.cards") 是 removed/added。另一方面,当我使用 表达式 len(deck.cards) 时,它 returns 所需的输出 (即甲板的更新大小)。

代码为:

# I've used only two suits and three ranks to explain this problem

suits = ('Hearts','Spades')
ranks = ('Queen','King','Ace')

class Card():
    
    def __init__(self,suit,rank):
        self.suit = suit
        self.rank = rank

class Deck():
    
    def __init__(self):
        # Create an empty deck and fill it with the available cards
        self.cards = []
        for suit in suits:
            for rank in ranks:
                self.cards.append(Card(suit,rank))
        
        self.length = len(self.cards)

    def deal_top_card (self):
        self.cards.pop(0)

deck = Deck()
# Removing Three cards one after the other
deck.deal_top_card()
deck.deal_top_card()
deck.deal_top_card()
print(f"Length according to length attribute = {deck.length}")
print(f"Length of the list of cards = {len(deck.cards)}")

上面代码的输出是:

Length according to length attribute = 6
Length of the list of cards = 3

您只是更新了 init() 方法中的 self.length。因此它不会在您每次弹出卡片时自行更新。 Init 仅在您创建对象时调用一次。您应该添加:

def deal_top_card (self):
    self.cards.pop(0)
    self.length = len(self.cards)

每次出卡更新长度

At 属性不会自行更新。看起来你想要一个 属性 或一个方法。

A 属性 是您想要访问 length 时要使用的东西,就好像它是一个属性一样。它还可以让您控制如果某些代码想要覆盖长度的值会发生什么:

class Deck:
    ....
    @property
    def length(self):
        return len(self.cards)

...
print(f"Length according to length property = {deck.length}")

一个方法类似,但你显式调用它:

class Deck:
    ....
    
    def length(self):
        return len(self.cards)

...
print(f"Length according to length method = {deck.length()}")

最后,你可以定义魔术__len__并调用len(deck),因为长度的概念适用于Python中的许多类型。

此外,您可能会认为 Deck 是一个与“卡片序列”非常相似的概念,因此将其作为 list 的子类可能有意义,在这种情况下您根本不需要定义长度方法。

你的问题是 length 只是一个属性。这意味着它在定义时收到一个值,并保留该值直到再次分配它。

但是 Python 有一个概念可以用属性做你想做的事:

class Deck():
    
    def __init__(self):
        # Create an empty deck and fill it with the available cards
        self.cards = []
        for suit in suits:
            for rank in ranks:
                self.cards.append(Card(suit,rank))
        
    @property
    def length(self):
        return len(self.cards)

    def deal_top_card (self):
        self.cards.pop(0)

一个属性作为一个特殊的成员,每次使用的时候实际执行一个方法。您现在可以成功使用:

deck = Deck()
# Removing Three cards one after the other
deck.deal_top_card()
deck.deal_top_card()
deck.deal_top_card()
print(f"Length according to length attribute = {deck.length}")
print(f"Length of the list of cards = {len(deck.cards)}")

并按预期获得:

Length according to length attribute = 3
Length of the list of cards = 3

顺便说一句,属性比那个更强大,并且可以在分配给或删除时调用其他方法。阅读 https://docs.python.org/3/library/functions.html#property 了解更多...