从类定义列表

时间:2018-01-01 17:28:03

标签: python python-3.x class

以下是Luciano Romalho的“Fluent Python”中的一副牌。 我希望我复制代码是可以的,我真的没有比这更简洁的类示例。

import collections
from random import choice

Card = collections.namedtuple('Card', ['rank', 'suit'])


class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()

    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits 
                       for rank in self.ranks]

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

    def __getitem__(self, position):
        return self._cards[position]

所以,这个类的一个实例将有52张卡片,每张卡片都是“卡片”对象中定义的命名元组。

我想画一张n张牌,以便它会反映在牌组中。

我尝试了以下内容:

def a_hand(deck, size):
    the_hand = []
    for n in range(size):
        c = choice(deck)
        the_hand.append(c)
        deck = [i for i in deck if i != c]
    return the_hand 

所以当我尝试时:

>> deck = FrenchDeck()
>> a = a_hand(deck, 5)

我伸出手,但甲板上没有动过:

>> hand
[Card(rank='9', suit='spades'),
 Card(rank='A', suit='hearts'),
 Card(rank='2', suit='diamonds'),
 Card(rank='8', suit='clubs'),
 Card(rank='10', suit='hearts')]

>> len(deck)
52

当我直接在interperter中尝试时:

>> c = choice(deck)
>> alt = [i for i in deck if i != c]

它有效:

>> len(alt)
51

我理解这是因为FrenchDeck的实例不受函数a_hand范围内发生的事情的影响。

这样做的方法是什么?我试图在类中定义一个dunder-delitem函数但是没有把它弄好,也不确定这是否是正确使用的函数以及它是在Card对象还是在FrenchDeck对象中定义的。

4 个答案:

答案 0 :(得分:1)

由于FrenchDeck实例未在a_hand函数内修改,因此您是对的。相反,您只能覆盖deck变量。为了实现您的目标,您可以例如将deal_hand方法添加到FrenchDeck类,这将返回给定大小的手并从卡片本身中删除选定的卡片。

答案 1 :(得分:1)

您创建一个新牌组而不是更新现有牌组。

deck = [i for i in deck if i != c]

这将创建一个由列表推导构建的 new 列表,并使deck指向它,而不是指向传递的原始列表。

如果要更改现有列表,则需要使用deck.remove(...)

(另外:尝试制作套牌和手牌,而不是列表。它更好地匹配域名。)

答案 2 :(得分:1)

你真的需要移动a_hand成为FrenchDeck的方法:

class FrenchDeck:
    # All previous code here, plus:

    def a_hand(self, size):
        the_hand = []
        for n in range(size):
            c = choice(self._cards)
            the_hand.append(c)
            self._cards.remove(c)
        return the_hand 

答案 3 :(得分:1)

当您从牌组中取出牌时,也要将其从牌组中取出。在list.pop中使用__getitem__

class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()

    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits 
                       for rank in self.ranks]

    def __len__(self):
        print(f'__len__ called: {len(self._cards)}') 
        return len(self._cards)

    def __getitem__(self, position):
        print(f'getting item {position}')
        return self._cards.pop(position)

def a_hand(deck, size):
    the_hand = []
    for n in range(size):
        print('getting another card')
        c = choice(deck)
        the_hand.append(c)
    return the_hand

deck = FrenchDeck()
a = a_hand(deck, 5)