Product


#1
def product(blargh):
    for x in blargh:
        blargh *= x
        
    return blargh

Hey,
I don't understand why this works, it shouldn't work. When I try to debug it with print, it throws some kind of infinite loop error.
Use small words please.


#2
blargh

is the list or sequence your are going through(iterating) to find your product to make it what you are doing is you are changing that each time in your for loop and then the interpreter comes back here

for x in blargh:

and then it sees a different list each time(initialization has to begin again).This messes it up. your best best
create a variable called total and set it to 1 then as you go through your list you multiply the current item in the list by total

Did that help?


#3

Should I have been incrementing total for each iteration as well? You're saying it's messed up, and I readily agree, but why did it pass the control then?

Does x start at 0 or 1 by the way? If it starts at 0, wouldn't that mess up a whole lot as well, seeing as anything times 0 is 0.

Or wait, do I turn the whole list into; the first item of the list times x? Is that what's happening?

Could we walk through the process in steps, what happens at the first iteration?


#5

def product(lst):
multiply = 1
for i in lst:
multiply *= i
return multiply

Hello Sir,

This is working perfectly fine. Thanks a lot for the idea... :smile:


#6

Necro'd thread, but it's already bumped up so oh well:

That's not quite what happens.

The way a for-loop works is that before it starts iterating, it requests an iterator from the value to be looped through.

An iterator is a value that produces values one at a time on request, until exhausted.

For example:

>>> i = iter(range(3))
>>> next(i)
0
>>> next(i)
1
>>> next(i)
2
>>> next(i)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

The StopIteration is how the for-loop can tell that the iterator is exhausted.

Once the for-loop has this iterator, it never asks for another, it will just use this iterator until it's exhausted.

So replacing the value of the variable no longer has any effect on the loop, as you can tell by:

>>> for n in a:
...  a = [100, 212, 378]
...  print n
... 
1
2
3

Let's assume that the list that's iterated through is a list of integers.

Multiplying a list by an integer has the following effect:

>>> [1, 2] * 3
[1, 2, 1, 2, 1, 2]

A new list is created that is the original list repeated multiple times.

If replacing the value of blargh has no effect on the loop, how does it become infinite?

Well, * is not the operator being used. *= is. Operators like -=, +=, *= etc are not completely equivalent to a = a + b, when the left operand is mutable (changeable) then they will change the current value instead of creating a new one.

So *= will modify the current list, the same list that the for-loop got an iterator from. And that iterator will produce values from its list until it's at the last element, which will never happen because the list is multiplied.

example of *= modifying the already existing list:

>>> a = [1]
>>> b = a # b now refers to the same list as a, not a copy
>>> a = a * 2
>>> print b # b is unaffected, because a new list was assigned to a
[1]


>>> a = [1]
>>> b = a
>>> a *= 2
>>> print b # since b is the same list and that list was modified, b is affected
[1, 1]

And here's to show that modifying the list associated to an iterator affects what the iterator yields:

>>> a = [1]
>>> i = iter(a)
>>> a.append(5) # modify the list after creating the iterator
>>> next(i)
1
>>> next(i)
5
>>> next(i)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

#7

Ohh Okay Got it.
The iterator generates the values(or the item in the iterable) upon request. so for the iterator to remember the original list despite it being changed would imply that the iterable we are looping through will be cached(saved) while the loop is running? if so then it will be a problem for very large lists or iterables.

Just as an side: If you have ever used sublime text, do you know you how to write a build configuration for jython (as of now i use eclipse but mine is loaded with plugins, make it really heavy to load)


#8

Yes, that iterable is stored behind the scenes. But there's only one copy of the list being iterated through.
The iterable itself doesn't store much if any data, it just knows how to get each next value from the thing it's supposed to iterate through. Like this:

>>> # Create an iterator for a list
... def iter_list(lst):
...     i = 0
...     while i < len(lst):
...         yield lst[i]
...         i += 1
... 
>>> # use it
... i = iter_list(range(5))
>>> next(i)
0
>>> next(i)
1
>>> next(i)
2
>>> next(i)
3
>>> next(i)
4
>>> next(i)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

I've briefly tried sublime but didn't get into its configuration stuff.
I don't really have any use for jython, but I'd be launching it from the command line, so my set-up process would be very brief:

$ sudo pacman -S jython
$ ln -s /opt/jython/bin/jython ~/bin/jython
$ jython
Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11) 
[OpenJDK 64-Bit Server VM (Oracle Corporation)] on java1.8.0_66
Type "help", "copyright", "credits" or "license" for more information.
>>>

..for some reason the executable is put in a slightly weird spot, so I create a symbolic link in my user's bin directory

Or on debian:

$ sudo apt-get install jython
$ jython
Jython 2.5.3 (, Oct 8 2014, 03:39:09) 
[OpenJDK 64-Bit Server VM (Oracle Corporation)] on java1.7.0_79
Type "help", "copyright", "credits" or "license" for more information.
>>>

#9

I took a slightly different approach:

def product(list):
    total = list[0]
    a = 1
    for n in list:

        total *= list[a]
        print total
        a += 1
        if a == len(list):
            break
    return total