[Tutor] access class through indexing?

Evert Rol evert.rol at gmail.com
Wed Aug 4 23:10:18 CEST 2010

>>> Further to my questions about overriding builtin methods earlier, how
>>> would I make a class able to be accessed and changed using index
>>> notation? For example, take the following:
>>> deck=CardPile(52) #creates a new deck of cards
>>> print(len(deck)) #prints 52, thanks to my __len__ function
>>> for c in deck: print c #also works thanks to __iter__
>>> print(deck[4]) #fails with a list index out of range error
>>> How would I get the last one working? I tried __getattr__(self, i),
>>> but it did not work. I want to be able to get an arbitrary item from
>>> the "pile" of cards (which can be a deck, a hand, whatever), and/or
>>> set an element. A "pile" is just a list of Card objects, so I would
>>> only need to use sequence indexing, not mapping functions.
>> Implement __getitem__(self, key) (See
>> http://docs.python.org/reference/datamodel.html#emulating-container-types )
>> If you want to support slicing (access like deck[0:10]), you'll need to
>> handle getting a slice object as the key in addition to accepting an integer
>> key.
>> If a pile is really "just" a list of cards, you may want to look into
>> inheriting from list instead of re-implementing all of the functionality on
>> your own.
> I tried this first, by typing
> class Pile(list):
> Doing this does not seem to work, though, since creating a pile of
> size 52 results in a list of size 0, unless I include the __len__
> function. I thought putting (list) in my class definition would
> automatically give me the functions of a list as well as anything I
> wanted to implement, but that does not seem to be the case.

That depends how you create the Pile of 52 cards: list(52) also doesn't generate 52 (random) items.
If you override __init__ to accept an integer that generates the cards for you, this should work.
Something like:

class Pile(list):
    def __init__(self, *args, **kwargs):
        if len(args) == 1 and isinstance(args[0], (int, long)):
            args = ([Card(i) for i in xrange(args[0])],)
        super(Pile, self).__init__(*args, **kwargs)

allows things like Pile(52), Pile([card1, card2, card3]), Pile(12)[0:3] etc.



More information about the Tutor mailing list