[Tutor] Strange list behaviour in classes
Dave Angel
davea at ieee.org
Thu Feb 25 12:22:30 CET 2010
James Reynolds wrote:
> Thank you! I think I have working in the right direction. I have one more
> question related to this module.
>
> I had to move everything to a single module, but what I would like to do is
> have this class in a file by itself so I can call this from other modules.
> when it was in separate modules it ran with all 0's in the output.
>
> Here is the code in one module:
>
> #import Statistics
>
> class Statistics:
> def __init__(self, *value_list):
> self.value = value_list
> self.square_list= []
> def mean(self, *value_list):
> try :
> ave = sum(self.value) / len(self.value)
> except ZeroDivisionError:
> ave = 0
> return ave
>
> def median(self, *value_list):
> if len(self.value) <= 2:
> n = self.mean(self.value)
> elif len(self.value) % 2 == 1:
> m = (len(self.value) - 1)/2
> n = self.value[m+1]
> else:
> m = len(self.value) / 2
> m = int(m)
> n = (self.value[m-1] + self.value[m]) / 2
> return n
> def variance(self, *value_list):
> average = self.mean(*self.value)
> for n in range(len(self.value)):
> square = (self.value[n] - average)**2
> self.square_list.append(square)
> try:
> var = sum(self.square_list) / len(self.square_list)
> except ZeroDivisionError:
> var = 0
> return var
>
> def stdev(self, *value_list):
> var = self.variance(*self.value)
> sdev = var**(1/2)
> return sdev
> def zscore(self, x, *value_list):
> average = self.mean(self.value)
> sdev = self.stdev(self.value)
> try:
> z = (x - average) / sdev
> except ZeroDivisionError:
> z = 0
> return z
>
>
>
> a = [1,2,3,4,5,6,7,8,9,10]
> stats = Statistics(*a)
> mean = stats.mean(*a)
> median = stats.median(*a)
> var = stats.variance(*a)
> stdev = stats.stdev(*a)
> z = stats.zscore(5, *a)
> print(mean, median, var, stdev, z)
> print()
>
>
>
> On Wed, Feb 24, 2010 at 7:33 PM, Alan Gauld <alan.gauld at btinternet.com>wrote:
>
>
>> "James Reynolds" <eire1130 at gmail.com> wrote
>>
>> I understand, but if self.value is any number other then 0, then the "for"
>>
>>> will append to the square list, in which case square_list will always have
>>> some len greater than 0 when "value" is greater than 0?
>>>
>>>
>> And if value does equal zero?
>>
>> Actually I'm confused by value because you treat it as both an
>> integer and a collection in different places?
>>
>>
>> Is this an occasion which is best suited for a try:, except statement? Or
>>
>>> should it, in general, but checked with "if's". Which is more expensive?
>>>
>>>
>> try/except is the Python way :-)
>>
>>
>> def variance(self, *value_list):
>>
>>> if self.value == 0:
>>> var = 0
>>> else:
>>> average = self.mean(*self.value)
>>> for n in range(len(self.value)):
>>> square = (self.value[n] - average)**2
>>> self.square_list.append(square)
>>> var = sum(self.square_list) / len(self.square_list)
>>> return var
>>>
>>>
>> --
>> Alan Gauld
>> Author of the Learn to Program web site
>> http://www.alan-g.me.uk/
>>
>
The indentation in your code is lost when I look for it -- everything's
butted up against the left margin except for a single space before def
variance. This makes it very hard to follow, so I've ignored the thread
till now. This may be caused by the mail digest logic, or it may
because you're posting online, and don't tell it to leave the code
portion unformatted. But either way, you should find a way to leave the
code indented as Python would see it. If you're posting by mail, be
sure and send it as text.
But a few things I notice in your code: You keep using the * notation
on your formal parameters. That's what turns a list into a tuple. And
you pass those lists into methods (like median()) which already have
access to the data in the object, which is very confusing. If the
caller actually passes something different there, he's going to be
misled, since the argument is ignored.
Also, in method variance() you append to the self.square_list. So if it
gets called more than once, the list will continue to grow. Since
square_list is only referenced within the one method, why not just
define it there, and remove it as a instance attribute?
If I were you, I'd remove the asterisk from both the __init__() method
parameter, and from the caller in top-level code. You're building a
list, and passing it. Why mess with turning it into multiple arguments,
and then back to a tuple? Then I'd remove the spurious arguments to
mean(), variance(), stdev() and zscore(). There are a few other things,
but this should make it cleaner.
DaveA
More information about the Tutor
mailing list