You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Blackjack游戏报错:AttributeError: 'set' object has no attribute 'append'

解决Blackjack游戏下注非5000金额时的AttributeError错误

问题场景

开发Python版二十一点游戏时,下注最大金额5000时运行正常,但输入其他金额时触发以下错误:

Traceback (most recent call last):
  File "c:\Users\Sufysam.DESKTOP-MTN757F\Desktop\Projects\blackjack.py", line 213, in <module>
    main()
  File "c:\Users\Sufysam.DESKTOP-MTN757F\Desktop\Projects\blackjack.py", line 55, in main
    move = getMove(playerHand, money - bet)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\Sufysam.DESKTOP-MTN757F\Desktop\Projects\blackjack.py", line 201, in getMove
    moves.append('(D)ouble down')
    ^^^^^^^^^^^^
AttributeError: 'set' object has no attribute 'append'

完整代码

import random, sys


HEARTS = chr(9829)
DIAMONDS = chr(9830)
SPADES = chr(9824)
CLUBS = chr(9827)

BACKSIDE = 'backside'


def main():
    print('''Blackjack:
          
    Rules:
        Try to get as close to 21 without going over.
        Kings, Queens, and Jacks are worth 10 points.
        Aces are worth 1 or 11 points.
        Cards 2 through 10 are worth their face value.
        (H)it to take another card.
        (S)tand to stop taking cards.
        On your first play, you can (D)ouble down to increase your bet
        but must hit exactly one more time before standing.
        In case of a tie, the bet is returned to the player.
        The dealer stops hitting at 17.''')
          
    money = 5000
    while True:
        if money <= 0:
            print('You\'re broke!')
            print("Good thing you weren't playing with real money")
            print('Thanks for playing!')
            sys.exit()


        print('Money:', money)
        bet = getBet(money)


        deck = getDeck()
        dealerHand = [deck.pop(), deck.pop()]
        playerHand = [deck.pop(), deck.pop()]


        print('Bet:', bet)
        while True:
            displayHands(playerHand, dealerHand, False)
            print()


            if getHandValue(playerHand) > 21:
                break


            move = getMove(playerHand, money - bet)


            if move == 'D':
                additonalbet = getBet(min(bet, (money - bet)))
                bet += additonalbet
                print('Bet increased to {}.'.format(bet))
                print('Bet:', bet)

            if move in ('H', 'D'):
                    newCard = deck.pop()
                    rank, suit = newCard
                    print('You drew a {} of {}.'.format(rank, suit))
                    playerHand.append(newCard)

                    if getHandValue(playerHand) > 21:
                        continue
            
            if move in ('S', 'D'):
                break
        

        if getHandValue(playerHand) <= 21:
            while getHandValue(dealerHand) < 17:
                print('Dealer hits...')
                dealerHand.append(deck.pop())
                displayHands(playerHand, dealerHand, False)

                if getHandValue(dealerHand) > 21:
                    break
                input('Press Enter to contiue...')
                print('\n\n')


        displayHands(playerHand, dealerHand, True)

        playerValue = getHandValue(playerHand)
        dealerValue = getHandValue(dealerHand)

        if dealerValue > 21:
            print('Dealer busts! You win ${}!'.format(bet))
            money += bet
        elif (playerValue > 21) or (playerValue < dealerValue):
            print(' You lost!')
            money -= bet
        elif playerValue > dealerValue:
            print('You won ${}!'.format(bet))
            money += bet
        elif playerValue == dealerValue:
            print('It\s a tie, the bet is returned to you')
        
        input('Press Enter to continue...')
        print('\n\n')


def getBet(maxBet):
    while True: 
        print('How much do you bet? (1-{}, or QUIT)'.format(maxBet))
        bet = input('> ').upper().strip()
        if bet == 'QUIT':
            print('Thanks for playing!')
            sys.exit()

        if not bet.isdecimal():
            continue

        bet = int(bet)
        if 1 <= bet <= maxBet:
            return bet
        

def getDeck():
    deck = []
    for suit in (HEARTS, DIAMONDS, SPADES, CLUBS):
        for rank in range(2, 11):
            deck.append((str(rank), suit))
        for rank in ('J', 'Q', 'K', 'A'):
            deck.append((rank, suit))
    random.shuffle(deck)
    return deck


def displayHands(playerHand, dealerHand, showDealerHand):
    print()
    if showDealerHand:
        print('Dealer: ', getHandValue(dealerHand))
    else:
        print('Dealer : ???')

        displayCards([BACKSIDE] + dealerHand[1:])


    print('PLAYER:', getHandValue(playerHand))
    displayCards(playerHand)


def getHandValue(cards):
    value = 0
    numberofAces = 0


    for card in cards:
        rank = card[0]
        if rank =='A':
            numberofAces += 1
        elif rank in ('K', 'Q', 'J'):
            value += 10
        else:
            value += int(rank)


    value += numberofAces
    for i in range(numberofAces):
        if value + 10 <= 21:
            value += 10

    return value

def displayCards(cards):
    rows = ['', '', '', '', '']

    for i, card in enumerate(cards):
        rows[0] += ' ___ '
        if card == BACKSIDE:
            rows[1] += '|## | '
            rows[2] += '|###| '
            rows[3] += '|_##| '
        else:
            rank, suit = card 
            rows[1] += '|{} | '.format(rank.ljust(2))
            rows[2] += '| {} | '.format(suit)
            rows[3] += '|_{}| '.format(rank.rjust(2, '_'))



    for row in rows:
        print(row)

        
def getMove(playerHand, money):
    while True:
        moves = {'(H)it', '(S)tand'}


        if len(playerHand) == 2 and money > 0:
            moves.append('(D)ouble down')


        movePrompt = ', '.join(moves) + '> '
        move = input(movePrompt).upper()
        if move in ('H', 'S'):
            return move
        if move == 'D' and '(D)ouble Down' in moves:
            return move
        

if __name__ == "__main__":
    main()

问题分析

  • 错误核心:getMove函数中,moves被定义为集合(set)(用{}包裹),而集合没有append方法,只有列表(list)才支持该操作。
  • 下注5000时无报错的原因:此时money - bet = 5000 - 5000 = 0,if len(playerHand) == 2 and money > 0:条件不成立,不会执行moves.append,因此不会触发错误。当下注其他金额时,money - bet > 0,条件成立,调用集合的append方法就会抛出AttributeError。
  • 额外问题:原代码中判断双倍下注时,字符串大小写不一致——moves里添加的是'(D)ouble down',但判断时写的是'(D)ouble Down',会导致该选项无法正常触发。

修复代码

修改getMove函数,将moves从集合改为列表,并修正大小写不一致问题:

def getMove(playerHand, money):
    while True:
        # 改为列表格式
        moves = ['(H)it', '(S)tand']

        if len(playerHand) == 2 and money > 0:
            moves.append('(D)ouble down')

        movePrompt = ', '.join(moves) + '> '
        move = input(movePrompt).upper()
        if move in ('H', 'S'):
            return move
        # 修正字符串大小写,与添加的内容一致
        if move == 'D' and '(D)ouble down' in moves:
            return move

内容的提问来源于stack exchange,提问作者Shayaan Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 16:47:11