Newbie: can't devide by function()

Alex Martelli aleax at aleax.it
Mon Mar 24 18:38:26 CET 2003


<posted & mailed>

Sven Brandt wrote:

> Hi,
> 
> I am trying to wirte a script that that first summs up some counters and
> than calculates the fraction of the total ammount for each object.
> 
> Funktion sum is fine. The funktion percent does not return anything. If

More likely, it returns the number 0.  What would you WANT it to return --
a list of fractional numbers, i.e. numbers < 1?  Or a list of percentages,
i.e. numbers < 100?  In either case, to return a list you must build a list.
And in your code, you don't.

> I change
> 
> "fraction=i.counter / summ()" to
> "fraction=i.counter * summ()"
> 
> I get a result.

Yes, a single (somewhat arbitrary) number.

> Question: Why can I multiply by the funktion sum but not devide by the
> function sum? (for sum !=0)

But of course you can!  However, unless you enable "true division"
in a recent release of python (with a -Qnew on the python command
line, or a "from __future__ import division" at the start of your
source code), you're getting backwards-compatible truncating division
when you divide two integers -- that is, in old Python (and still
today, for backwards compatibility, unless you explicitly enable the
new mechanism), a division such as 2/3 produces the result of 0.

So, unless you want to enable the new mechanism, you need to turn
either the divisor, or the dividend, or both, into floats rather
than integers -- e.g., calling float(x) is the simplest way to
get the equivalent of x but as a floating point number rather than
as an integer.

Alternatively, you could multiply the numerator (dividend) by 100
before dividing, to get integer percentages.

But let's critique your code a bit more...:


> Script:
> def summ():
> 
> """iterate over some Objects and add up their properties
>       'counter'(type=int) """
> 
>    total_number=0
>    for i in container.objectValues(['Folder']):
>      total_number= total_numer + i.counter
>    return total_number

This is presumably correct.


> def percent():
> 
> """ calculate the fraction of each object """
> 
>    fraction=0
>    for i in container.objectValues(['Folder']):
>      fraction=i.counter / summ()
>    return fraction

This can't be correct.  You're calling summ() N times,
duplicating a lot of work -- and doing N divisions, and
of course ignoring the results of the first N-1 of them,
since you're rebiding name 'fraction' to each new
result in succession only the last one will "survive"
and be returned.  Even if each division was correctly
using floating point, you'd still only be returning the
result of the last one, wasting all the rest of the
computation.

Since you have SEVERAL objects, you presumably want
a LIST of results, say as integer percentages:

def percents():
   total = summ()
   results = []
   for i in container.objectValues(['Folder']):
      results.append(100*i / total)
   return results

or equivalently, with a list comprehension:

def percents():
   total = summ()
   return [100*i/total for i in container.objectValues(['Folder'])]


> return fraction()

...and this latest little tidbit makes no sense at all.
The return statement is only allowed within a function,
and besides there IS no callable named fraction for you
to call.  I really don't get this.


Alex





More information about the Python-list mailing list