Question

Is it possible to change something in the init function of a class?

Lets say I have a class called "deck" which, when initialized, creates a list of 52 card objects.

Now I want to make another class called "even" which inherits from "deck" class and creates a deck of card objects BUT eliminates all cards with a number 2 (so spades, hearts, etc) from the inherited "deck".

I have been having a lot of trouble with this because when I try to modify the inherited list, regardless of what I try, python will return an error, usually with 'NoneType' being the main root of the problem. Here is the code for the "even" class init:

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

It is worth noting that my card class has a method rank() which will return the rank of the card as an int.

Regardless of all the things I have tried, there is always something wrong with it. Sometimes it will say "'NoneType' object is not iterable" or "subscripable" and when I check the type() of x it is a NoneType. I have done a lot of searching around but nothing is making sense to me about NoneType or what I should do to fix it.

If I remove the for loop then the code will create a deck of 52 cards as expected, but I need to filter out the 2's for example.

Edit: this is my deck class init:

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

If you cant tell, Card is also a class and the init of deck creates 52 card objects

Was it helpful?

Solution

So assuming a simple version of your Deck baseclass, inheriting an modifying the list of cards stored in the baseclass could be done something like:

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

EDIT: updating for the added information in the question:

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]

OTHER TIPS

Given the way you're doing things in Deck, what you would have to do in your subclass is:

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

Since your object inherits from list, it is a list, and so you can modify it by assigning directly to a slice.

However, this is probably not the best way to design your class. Instead of inheriting from list, it is usually easier to store a list internally and modify it to do what you want.

Note that you should not return anything from __init__. __init__ does not return the value of the object; it is supposed to modify self to set whatever it wants, and always return None. The only reason you're getting away with returning in Deck is that you return the value of a superclass __init__, which itself returns None as a good __init__ should.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top