我正在尝试创建一个随机处理两张卡片的程序。但是,它不断出现错误:
AttributeError: type object `CardPack` has no attribute `suits`
我不确定,但我认为这意味着课程CardPack
没有值suits
。但是,在__init__
函数中,它已被定义。我完全被难倒了。
班级代码:
import random
class CardPack:
def __init__(self):
self.cardsClubs = ["A C", "2 C", "3 C", "4 C", "5 C", "6 C", "7 C", "8 C", "9 C", "10 C", "J C", "Q C", "K C"]
self.cardsSpades = ["A S", "2 S", "3 S", "4 S", "5 S", "6 S", "7 S", "8 S", "9 S", "10 S", "J S", "Q S", "K S"]
self.cardsHearts = ["A H", "2 H", "3 H", "4 H", "5 H", "6 H", "7 H", "8 H", "9 H", "10 H", "J H", "Q H", "K H"]
self.cardsDiamonds = ["A D", "2 D", "3 D", "4 D", "5 D", "6 D", "7 D", "8 D", "9 D", "10 D", "J D", "Q D", "K D"]
self.cardsDealt = []
self.suits = ["C", "S", "H", "D"]
def getRandomCards(self):
card = ""
if random.choice(self.suits) == "C":
card = random.choice(self.cardsClubs)
elif random.choice(self.suits) == "S":
card = random.choice(self.cardsSpades)
elif random.choice(self.suits) == "H":
card = random.choice(self.cardsHearts)
elif random.choice(self.suits) == "D":
card = random.choice(self.cardsDiamonds)
else:
pass
return card
def deal(self):
cards = 1
while cards != 3:
self.cardsDealt[cards] = self.getRandomCards(self)
return self.cardsDealt
运行的文件创建实例:
#DEALING TEST
from DeckDealer import CardPack
Dealer = CardPack
cards = Dealer.deal(CardPack)
print("Your cards are %s and %s!" % (cards[1], cards[2]))
答案 0 :(得分:3)
您不是在这里创建实例:
Dealer = CardPack
这只是对该类的另一个引用( type ),因此也不会调用__init__
方法。
调用类来生成实例:
Dealer = CardPack()
答案 1 :(得分:2)
Dealer = CardPack
此行不会创建CardPack
类型的实例,它只会复制对它的引用。因此,当您再调用Dealer.deal()
时,您实际上正在执行CardPack.deal()
,它无法访问实例属性。
相反,您应该创建一个实例,然后在该实例上调用该方法:
dealer = CardPack()
cards = dealer.deal()
在这种情况下,同样重要的是要注意,要调用方法,您可以不传递self
的值。在实例上调用方法时,会隐式设置self
。因此,当您执行dealer.deal()
时,self
会自动设置为经销商实例。如果您要调用dealer.deal(dealer)
,则会传递该方法没有的第二个参数,因此您会收到错误消息。这也是getRandomCards
中deal
来电的问题:self.getRandomCards(self)
会将self
设置为第二个参数,从而导致错误。只是做self.getRandomCards()
就是你想做的事。
话虽如此,请注意您的deal
方法会有无限循环,因为只要cards
不是3,您就会继续迭代,但您永远不会更改cards
的值。所以你可能想要增加循环中的值。但即便如此,在空列表中访问cardsDealt[cards]
也会导致IndexError,因此您也想修复它。您可以先重置列表,然后只需append
张新卡,但更好的方法是只创建一张包含3张卡的新列表。您可以使用列表推导来简化和简短:
def deal(self):
self.cardsDealt = [self.getRandomCards() for card in range(3)]
return self.cardsDealt
最后,您的getRandomCards
可能无法完全按照您的预期执行操作。通常,您会期望每张卡都有相同的机会。你做的方式是,俱乐部卡有1/4的机会,黑桃卡有3/16的机会,红心卡的机会为9/64,钻石卡的机会为27/256。这样就有可能获得81/256 no card 。这显然是不正确的。
发生这种情况的原因是你为每次测试做出随机选择。因此,为了测试您是否获得了俱乐部卡,您可以做出选择(1/4机会)。如果你没有得到一个(3/4的机会),你可以做出另一个选择来获得一张黑桃卡(1/4的机会;所以总共3/4 * 1/4)等等。相反,你会想做选择只需,然后将该结果重用于子类别:
def getRandomCards(self):
# only make *one* random choice for the suit
suit = random.choice(self.suits)
if suit == "C":
return random.choice(self.cardsClubs)
elif suit == "S":
return random.choice(self.cardsSpades)
elif suit == "H":
return random.choice(self.cardsHearts)
elif suit == "D":
return random.choice(self.cardsDiamonds)
这也使你无法从方法中获得随机牌,因为你总是得到四件套装中的一件。
最后2,正如gboffi在评论中提到的那样,你没有任何保护措施阻止你获得多张相同的卡片。可能(不太可能但仍然可能)从getRandomCards()
获得相同卡的三倍,这在大多数游戏中是不可能的。
为防止这种情况发生,您可以在所有卡片列表中使用random.sample
。这将为您提供三个(或任何数量)明确不同的卡。它还允许你有一个真正的“牌组”,你可以从牌组中取出牌,直到你重新开始游戏。
通过您的设置,您可以制作一个像这样的新套牌:
self.deck = self.cardsClubs + self.cardsSpades + self.cardsHearts + self.cardsDiamonds
这基本上只是组合了所有四个卡片列表,创建了一个可以随后绘制的新卡片列表。要从中抽取三个,您可以使用random.sample
,如下所示:
drawnCards = random.sample(self.deck, 3)
然后你可以从牌组中删除那些牌:
for card in drawnCards:
self.deck.remove(card)
另一种方式是更贴近地遵循真实的方式。而不是从(分类的)牌组中抽取随机牌,你可以先将牌组洗牌,然后从顶部抽牌。要随机播放列表,您可以使用random.shuffle
,并从列表中绘制和删除卡片,您可以使用list.pop
:
# create the deck
self.deck = self.cardsClubs + self.cardsSpades + self.cardsHearts + self.cardsDiamonds
# shuffle the deck
random.shuffle(self.deck)
# and then draw three cards from it
drawnCards = [self.deck.pop() for i in range(3)]