type object x没有属性y

时间:2014-11-29 13:08:50

标签: python oop

我正在尝试创建一个随机处理两张卡片的程序。但是,它不断出现错误:

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]))

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),则会传递该方法没有的第二个参数,因此您会收到错误消息。这也是getRandomCardsdeal来电的问题: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)]