我正在尝试无重复地遍历一副纸牌。
以下是代码:
import random
class Cards:
# Where prefix d is Diamonds, h is Hearts, s is Spades and c is Clubs
total_cards = [{2: 'd2', 3: 'd3', 4: 'd4', 5: 'd5', 6: 'd6', 7: 'd7', 8: 'd8', 9: 'd9', 10: 'd10', 11: 'dJack',
12: 'dQueen', 13: 'dKing', 14: 'dAce'},
{2: 'h2', 3: 'h3', 4: 'h4', 5: 'h5', 6: 'h6', 7: 'h7', 8: 'h8', 9: 'h9', 10: 'h10', 11: 'hJack',
12: 'hQueen', 13: 'hKing', 14: 'hAce'},
{2: 's2', 3: 's3', 4: 's4', 5: 's5', 6: 's6', 7: 's7', 8: 's8', 9: 's9', 10: 's10', 11: 'sJack',
12: 'sQueen', 13: 'sKing', 14: 'sAce'},
{2: 'c2', 3: 'c3', 4: 'c4', 5: 'c5', 6: 'c6', 7: 'c7', 8: 'c8', 9: 'c9', 10: 'c10', 11: 'cJack',
12: 'cQueen', 13: 'cKing', 14: 'cAce'}]
def random_pick(self): # Method to randomly pick a card from the deck
choice = random.choice(random.choice(self.total_cards))
for v in self.total_cards: # to retrieve the corresponding `key` for `choice`
for i in v.values():
if choice == i:
k = v[i]
v.pop(k)
print(choice) # To print the random card picked from the deck
print(self.total_cards) # To print the updated Deck after picking the card
c = Cards()
c.random_pick()
我要尝试的想法是,一旦拿起卡,就应将其从卡座中取出。
这是错误:
Traceback (most recent call last):
File "F:/Blackjack/Base/Cards.py", line 30, in <module>
c.random_pick()
File "F:/Blackjack/Base/Cards.py", line 17, in random_pick
choice = random.choice(random.choice(self.total_cards))
File "C:\Users\Python\Python37-32\lib\random.py", line 262, in choice
return seq[i]
KeyError: 0
据我了解,KeyError
是在现有键集中找不到映射(字典)键时引发的异常。但是我的 IF LOOP 仅在条件choice == i
下才是 TRUE ,只有在这种情况下,才应该启动pop()。
我尝试了上面的代码,但没有在代码中使用pop()方法,并且代码运行正常,每次运行后都会生成随机卡片。
答案 0 :(得分:3)
如果您多次尝试执行代码,则会发现您不会每次都收到此错误。有时它会越过终点线
choice = random.choice(random.choice(self.total_cards))
,然后在代码中再次遇到另一个错误。
那是怎么回事?我假设random.choice(self.total_cards)
可以正常工作,并返回total_cards
列表中的四个卡片组之一。您将该卡组表示为字典。
在一个更简单的示例上,让我们看看random.choice
对词典的作用:
>>> import random
>>>
>>> random.seed(0) # for reproducability
>>> random.choice({1:2, 3:4})
2
嗯,很奇怪,它返回了其中一个值。我曾期望其中一个键,例如在不调用.items()
或.values()
的情况下遍历字典时。
>>> [i for i in {1:2, 3:4}]
[1, 3]
让我们再试一次:
>>> random.seed(42) # for reproducability
>>> random.choice({1:2, 3:4})
KeyError: 0
奇怪,不是吗? 0
既不在值中也不在键中。它是哪里来的?
让我们看看如何实现random.choice
。在IPython中,我可以这样获得其源代码:
In [1]: import random
In [2]: random.choice??
要获取系统上的代码,您还可以查看错误消息中提到的文件:第C:\Users\Python\Python37-32\lib\random.py
行第262行。
在Python 3.6.6(我系统上的版本)上,源代码为:
def choice(self, seq):
"""Choose a random element from a non-empty sequence."""
try:
i = self._randbelow(len(seq))
except ValueError:
raise IndexError('Cannot choose from an empty sequence') from None
return seq[i]
私有方法random._randbelow
包含说明
返回范围为[0,n)的随机整数。如果n == 0,则引发ValueError。
虽然这对于序列(例如列表,集合或元组)很好用,但我想您会明白为什么当seq
恰好是字典(或任何其他映射)时,它根本无法做正确的事情):
需要
序列的长度(
len(seq)
)
(也适用于词典),然后
生成一个介于0(含)和该长度(不含)之间的随机整数(这就是
self._randbelow
的作用)
所以这将是
序列中随机元素的0索引位置
然后
使用该随机整数索引序列(
seq[i]
)并返回该值(return
)
对字典不起作用,因为它们是
由其键索引。
这也是为什么我们有时没有收到错误,而是random.choice
返回其中一个字典值的原因:当整数用作a
随机位置
也恰好是字典的键之一,它只会返回相应的值。如果碰巧不是我们的任何键(如果所有键都是非整数(例如字符串),那么b.t.w.总是这样),则会出现KeyError
。
答案 1 :(得分:1)
快速解答:random.choice()用于序列即列表,如文档中所述。
长答案:请参见das-g's answer。
答案 2 :(得分:0)
我认为列表会更好,这是我的处理方式:
from random import shuffle
class Cards:
def __init__(self): #example deck with just some cards
self.total_cards = ['c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'c10']
shuffle(self.total_cards) #shuffle the deck of cards
def random_pick(self): #Method to randomly pick a card from the deck
print(self.total_cards[len(self.total_cards)-1]) #To print the last card from your deck, which will be removed by pop() command
self.total_cards.pop()
print(self.total_cards) #To print the updated Deck after pop() the last card
c = Cards()
for _ in range(3): # picking 3 random cards for demostration
c.random_pick()
答案 3 :(得分:0)
尝试我的解决方案:
import random
import numpy as np
class Cards:
# Where prefix d is Diamonds, h is Hearts, s is Spades and c is Clubs
total_cards = [{2: 'd2', 3: 'd3', 4: 'd4', 5: 'd5', 6: 'd6', 7: 'd7', 8: 'd8', 9: 'd9', 10: 'd10', 11: 'dJack',
12: 'dQueen', 13: 'dKing', 14: 'dAce'},
{2: 'h2', 3: 'h3', 4: 'h4', 5: 'h5', 6: 'h6', 7: 'h7', 8: 'h8', 9: 'h9', 10: 'h10', 11: 'hJack',
12: 'hQueen', 13: 'hKing', 14: 'hAce'},
{2: 's2', 3: 's3', 4: 's4', 5: 's5', 6: 's6', 7: 's7', 8: 's8', 9: 's9', 10: 's10', 11: 'sJack',
12: 'sQueen', 13: 'sKing', 14: 'sAce'},
{2: 'c2', 3: 'c3', 4: 'c4', 5: 'c5', 6: 'c6', 7: 'c7', 8: 'c8', 9: 'c9', 10: 'c10', 11: 'cJack',
12: 'cQueen', 13: 'cKing', 14: 'cAce'}]
_showed = 0
def __init__(self):
self._shuffle_cards()
self.pointers = [0 for _ in range(len(self.total_cards))]
def _shuffle_cards(self):
for i, v in enumerate(self.total_cards):
temp = list(v.items())
self._showed += 1
np.random.shuffle(temp)
self.total_cards[i] = temp
def random_pick(self):
choice = random.choice(range(len(self.total_cards)))
while self.pointers[choice] >= len(self.total_cards[choice]) and self._showed > 0:
choice = random.choice(self.total_cards)
self.pointers[choice] += 1
if self._showed == 0:
print('Nothing cards to show')
else:
self._showed -= 1
print(self.total_cards[choice][self.pointers[choice]][1])
c = Cards()
c.random_pick()