views:

71

answers:

4

I'm tasked with creating a model of a cage of hardware. Each cage contains N slots, each slot may or may not contain a card.

I would like to model the cage using a list. Each list index would correspond to the slot number. cards[0].name="Card 0", etc.

This would allow my users to query the model via simple list comprehensions. For example:

for card in cards:
    print card.name

My users, which are not sophisticated Python users, will be interacting with the model in real-time, so it is not practical to have the list index not correspond to a populated card. In other words, if the user removes a card, I need to do something that will indicate that the card is not populated -- my first impulse was to set the list item to 'None'.

The Bossman likes this scheme, but he's not crazy about the list comprehension above failing if there is a card missing. (Which it currently does.) He's even less supportive of requiring the users to learn enough Python to create list comprehension expressions that will ignore 'None'.

My thought was to sub-class the 'list' class, to create a "newclass". It would work exactly like a list, except 'for card in cards' would only return members not set to 'None'.

Will someone please demonstrate how to overload the list class so that list comprehensions called on the subclass will ignore 'None'? (My Python skills have so far begun to break down when I attempt this.)

Can anyone suggest a better approach?

Thanks, JS

+1  A: 

You can do something like this to get the names if you're using 2.6 or newer:

names = [x.name for x in cards if x is not None]

That should get close to what you're after I think.

g.d.d.c
+7  A: 
>>> class MyList(list):
...     def __iter__(self):
...         return (x for x in list.__iter__(self) if x is not None)
... 
>>> 
>>> ml = MyList(["cat", "dog", None, "fox"])
>>> for item in ml:
...     print item
... 
cat
dog
fox

>>> [x for x in ml]
['cat', 'dog', 'fox']
>>> list(ml)
['cat', 'dog', 'fox']
gnibbler
D'oh! I was *so* close... the only difference between mine and yours is that yours ... works. ;-) And it works well! Great job! Thanks!
JS
@JS, you're welcome
gnibbler
You forgot `super()`.
Aaron Gallagher
A: 

Perhaps define a function (assuming cards is a global variable?!?):

def pcards():
    for card in cards:
        if card:
            print card.name

so your users can simply type pcards() to get a listing.

unutbu
+2  A: 

You could provide a generator/iterator for this.

def installed(cage):
    for card in cage:
        if card:
            yield card

cards = ["Adaptec RAID", "Intel RAID", None, "Illudium Q-36 Explosive Space Modulator"]

# print list of cards
for card in installed(cards):
    print card
kindall
+1 for use of "Illudium Q-36 Explosive Space Modulator" :-)
JS
I think your code to print the numbered list is broken. It shows the Q-36 in slot 2
gnibbler
Quite right, there's no way to do that with what I've given, so I removed it. You'd need a replacement enumerate function. Which I will leave as an exercise for the reader. :-)
kindall