[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