5

I have a class representing items of stock and their value:

class stock:
    def __init__(self, stockName, stockType, value):
        self.name = stockName
        self.type = stockType
        self.value = value

I have loads of stock so I make a list of stock objects from which I can access the value of individual items e.g stockList[12].value

I want to add up the value of all stock items which are 'shirts'. The following works fine:

shirtValue = sum([s.value for s in stockList if s.value == 'shirt'])

OK, fine. But now I have a list of stockType and wish to sum the value of items which match a particular entry in the stockType list e.g.:

stockTypeValue[0] = sum([s.value for s in stockList if s.value == stockType[0]])

where stockType[0] = 'shirt'This doesn't work. I know Why - it is because in Python 3 list comprehensions have their own scope (See detailed answer here: Accessing class variables from a list comprehension in the class definition )

My question is this: The code I have written, which I think would work in Python 2 looks great, it is clean, easy to understand, and to the untrained eye looks very pythonic.

But I can't figure out how to do the same thing in a nice pythonic way in Python 3. I'm going back to big loop structures.

What is the best way to do this in Python 3?

* Edit * Error messages:

Here is an example of what I am trying to do:

stockList=[]
stockList.append(stock('product A', 'shirt', 53.2))
stockList.append(stock('product B', 'hat', 20.2))

sum([s.value for s in stockList if s.type=='shirt'])

output:

Out[5]: 53.3

But if I put 'shirt' into a variable:

stockType = 'shirt'
sum([s.value for s in stockList if s.type==stockType])

output:

Traceback (most recent call last):
 File "<console>", line 1, in <module>
 File "<console>", line 1, in <listcomp>
NameError: name 'stockType' is not defined
Community
  • 1
  • 1
simonagill
  • 61
  • 1
  • 3
  • 1
    Where is `stockList` defined? And can you please expand on "doesn't work": do you get an exception? (If so, please show the traceback.) Or is there some other failure mode? – Mark Dickinson Mar 27 '15 at 09:13
  • 1
    Are you sure it's not just failing due to your unbalanced [] ? – Paul Mitchell Mar 27 '15 at 09:18
  • 3
    Besides unbalanced [], you might have issues with you `self.type = value` and `s.value==stockType[0]`. Can you do the minimal non working example and then copy paste both full code and example? – Francis Colas Mar 27 '15 at 09:22
  • 1
    Voting to close: there's not enough information in the question to be able to guess amongst the many possible things that might be going wrong. @simonagill: You can help us help you by showing the traceback. Have a look at http://stackoverflow.com/help/mcve, too. – Mark Dickinson Mar 27 '15 at 09:33
  • @MarkDickinson I've added some traceback information. Does this help? – simonagill Mar 27 '15 at 09:40
  • @PaulMitchell apologies - I've corrected that. No it wasn't that which was causing me a problem. – simonagill Mar 27 '15 at 09:41
  • @simonagill: It definitely helps; thank you! (Close vote retracted.) Though I can't reproduce your problem: typing the lines you give at the prompt works fine for me (Python 3.4). You've got a missing `)` on your first `append`, by the way. – Mark Dickinson Mar 27 '15 at 09:43
  • Can you clarify the context of your `stockType = 'shirt'; sum(...)` statements? Are you executing those at interactive shell level? Within a function / method? As @poke's answer shows, there's no exception when executing those statements directly at the prompt. – Mark Dickinson Mar 27 '15 at 10:07
  • @MarkDickinson Yes I currently have the stock class in a file called testWorking.py which I have imported. Then I have typed the code including below my EDIT statement at the prompt. I have also saved the code as a script and tried to run that with the same result. – simonagill Mar 27 '15 at 10:25

1 Answers1

2

This doesn't work. I know Why - it is because in Python 3 list comprehensions have their own scope (See detailed answer here: Accessing class variables from a list comprehension in the class definition )

That’s actually not true. I mean, of course that answer in that question is correct but that’s not what is happening here. That question is only relevant for expressions that happen in the class body at definition time. If you are e.g. within a method though then there is no problem at all.

However, what likely fails (“likely” because you didn’t supply the error message), is that the target list stockTypeValue isn’t initialized.

>>> stockTypeValue[0] = 'something'
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    stockTypeValue[0] = 'something'
NameError: name 'stockTypeValue' is not defined

So we can define it now and assign an empty list; but the list is still empty:

>>> stockTypeValue = []
>>> stockTypeValue[0] = 'something'
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    stockTypeValue[0] = 'something'
IndexError: list assignment index out of range

Instead, you would have to append the result to the empty list:

>>> stockTypeValue.append('something')
>>> stockTypeValue[0]
'something'

Replaying your example:

>>> stockList = []
>>> stockList.append(stock('product A', 'shirt', 53.2))
>>> stockList.append(stock('product B', 'hat', 20.2))
>>> sum([s.value for s in stockList if s.type == 'shirt'])
53.2
>>> stockType = 'shirt'
>>> sum([s.value for s in stockList if s.type == stockType])
53.2
Community
  • 1
  • 1
poke
  • 369,085
  • 72
  • 557
  • 602