如何在子类的__init__方法中修改继承的列表?

1 投票
2 回答
2738 浏览
提问于 2025-04-18 03:28

能不能在一个类的init函数里改点东西呢?

假设我有一个叫“deck”的类,这个类在初始化的时候会创建一个包含52张卡片对象的列表。

现在我想创建另一个叫“even”的类,这个类是从“deck”类继承来的,它会创建一副卡片对象,但会把所有数字为2的卡片(比如黑桃、红心等)从继承的“deck”中去掉。

我在这方面遇到了很多麻烦,因为每当我尝试修改继承来的列表时,不管我怎么做,Python总是会报错,通常是‘NoneType’的问题。下面是“even”类的init代码:

def __init__(self):
    x = Deck.__init__(self)
    for card in x:
        if card.rank() == 2:
            x.pop(card)
    return x

值得注意的是,我的卡片类有一个方法rank(),这个方法会返回卡片的等级,类型是整数。

无论我尝试了什么,总是会出现问题。有时候会提示“'NoneType'对象不可迭代”或者“不可下标”,当我检查x的类型时,它是NoneType。我搜索了很多资料,但对NoneType和我该怎么解决这个问题都没有搞明白。

如果我去掉for循环,那么代码就会如预期那样创建52张卡片,但我需要过滤掉数字2的卡片。

编辑:这是我的deck类的init

class Deck(list):
    def __init__(self):
        return list.__init__(self, [Card(i) for i in range(52)])

如果你看不出来,Card也是一个类,而deck的init会创建52个卡片对象。

2 个回答

2

根据你在 Deck 中的做法,你在子类中需要做的事情是:

def __init__(self):
    Deck.__init__(self)
    self[:] = [card for card in self if card.rank() != 2]

因为你的对象是从 list 继承来的,所以它就是一个列表,你可以通过直接给一个切片赋值来修改它。

不过,这可能不是设计你这个类的最佳方式。通常来说,不是直接继承 list,而是内部存储一个列表,然后对这个列表进行修改,会更简单。

另外,记住在 __init__ 方法中不要返回任何东西。__init__ 方法并不是用来返回对象的值的;它的作用是修改 self,设置你想要的内容,并且总是返回 None。你在 Deck 中能返回值的唯一原因是你返回了父类的 __init__ 的值,而这个父类的 __init__ 方法本身应该返回 None,这是一个好的 __init__ 方法应该做到的。

5

假设你有一个简单的Deck基础类,想要在这个基础上修改存储的卡片列表,可以这样做:

# simple baseclass that contains a list of Card objects
class Deck(object):
    def __init__(self):
        self.deck = [...] # some list of cards

# a class to hold only even cards
class Even(Deck)
    def __init__(self):
        # use super to instantiate the baseclass
        super(Even,self).__init__(self)

        # create a local instance of `deck` that contains only even cards
        # the base set of cards can still be acessed via super(Even,self).deck
        self.deck = [card for card in self.deck if card.rank() != 2]

编辑:根据问题中新增的信息进行更新:

class Deck(list):
    def __init__(self):
        super(Deck,self).__init__([Card(i) for i in range(52)])

class Even(Deck)
    def __init__(self):
        super(Even,self).__init__(self)
        [self.remove(card) for card in self if card.rank()==2]

撰写回答