【问题标题】:Python subclass invoking method from parent classPython子类从父类调用方法
【发布时间】:2013-12-06 11:26:11
【问题描述】:

我目前正在自学 Python,并且上过关于继承的课程,所以这是我第一次接触子类。我正在从“Think Python”一书中学习,这个例子是关于创建代表扑克牌、甲板、手牌等的类。下面的例子是从这本书中复制的(我自己添加了一个或两个方法,作为练习):

import random
from operator import itemgetter, attrgetter

class Card:
"""represents a standard playing card."""
    def __init__(self, suit=0, rank=2):
        self.suit = suit
        self.rank = rank

    suit_names = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
    rank_names = [None, 'Ace', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King']

    def __str__(self):
        return '%s of %s' % (Card.rank_names[self.rank], Card.suit_names[self.suit])

    def __cmp__(self, other):
        t1 = self.suit, self.rank
        t2 = other.suit, other.rank
        return cmp(t1, t2)

class Deck:
"""represents a standard deck of cards"""
    def __init__(self):
        self.cards = []
        for suit in range(4):
            for rank in range(1, 14):
                card = Card(suit, rank)
                self.cards.append(card)

    def __str__(self):
        res = []
        for card in self.cards:
            res.append(str(card))
        return '\n'.join(res)

    def pop_card(self):
        return self.cards.pop()

    def add_card(self):
        self.cards.append(card)

    def shuffle(self):
        random.shuffle(self.cards)

    def sort(self):
        self.cards.sort(key=attrgetter('suit', 'rank'))

class Hand(Deck):
"""represents a hand of playing cards"""
    def __init__(self, label=''):
        self.cards = []
        self.label = label

    def move_cards(self, hand, num):
        for i in range(num):
            hand.add_card(self.pop_card())

我的问题是 Hand 子类方法。如果我尝试从 Hand 子类调用 move_cards 方法,例如使用a = Deck()、b = Hand(),尝试调用move_cards(b,2) 或a.move_cards(b,2) 给我同样的AttributeError: 'Deck' object has no attribute 'move_cards'。

为什么会发生这种情况或我做错了什么?谢谢。

【问题讨论】:

  • 您的a 对象仍然是Deck 实例,因此它对move_cards 方法一无所知。使用继承时,子类继承超类的行为,而不是相反。

标签: python inheritance python-3.x parent-child subclass


【解决方案1】:

move_cards 只为子类Hand 定义,而不是父类Deck。

我认为示例中的继承顺序令人困惑 - Hand 并不真的是 Deck 的子类,而是它们都应该是公共卡片集合的子类(Stack 说)。例如(未测试):

class Stack:
"""represents a collection of cards"""
    def __init__(self):
        self.cards = []

    def __str__(self):
        res = []
        for card in self.cards:
            res.append(str(card))
        return '\n'.join(res)

    def pop_card(self):
        return self.cards.pop()

    def add_card(self):
        self.cards.append(card)

    def shuffle(self):
        random.shuffle(self.cards)

    def sort(self):
        self.cards.sort(key=attrgetter('suit', 'rank'))

    def move_cards(self, dest, num):
        for i in range(num):
            dest.add_card(self.pop_card())

class Deck(Stack):
"""represents a deck of playing cards"""
    def __init__(self):
        Stack.__init__(self)
        for suit in range(4):
            for rank in range(1, 14):
                card = Card(suit, rank)
                self.cards.append(card)

class Hand(Stack):
"""represents a hand of playing cards"""
    def __init__(self, label=''):
        Stack.__init__(self)
        self.label = label

注意子类Hand 和Deck 的重写构造函数如何使用Stack.__init__(self) 显式调用父构造函数。这将以相同的方式为每个成员初始化 self.cards 成员。

【讨论】:

  • 非常感谢这位先生!我现在看到我的阅读方式的错误,书中清楚地写着 move_cards 应该在类 Deck 内!
  • ...但现在我收到“TypeError: add_card() 需要 1 个位置参数但给出了 2 个”(来自我的代码示例)
  • 您的add_card 方法需要一个名为card 的参数。将定义更改为add_card(self, card) 并使用a.add_card(c) 调用它
  • 感谢您的建议!至于你的代码,当它需要用卡片填充卡片组时它会失败,card = Card(suit, rank) 的初始化由于缺少 Card 类而失败。
  • 是的,我没有费心将 Card 类包括在内,因为它看起来还不错。只需将 Card 的原始代码粘贴到我修改后的代码上方即可。
猜你喜欢
  • 2017-11-09
  • 2012-02-22
  • 2014-07-07
  • 1970-01-01
  • 2014-06-11
  • 1970-01-01
  • 1970-01-01
  • 2014-09-23
  • 2012-07-13
相关资源
最近更新 更多