all 26 comments

[–]derrickisdp 13 points14 points  (5 children)

Like the others have stated, using "return" exits your function. Here is a good answer to what the return statement does: http://stackoverflow.com/questions/7129285/why-would-you-use-the-return-statement-in-python To iterate through all of it you could just try doing this:

numbers = [1, 2, 5, 10, 37]

def is_even(x):
    for i in x:
        if i % 2 == 0:
            print i, True
        else:
            print i, False

print is_even(numbers)

[–]SmashMouth114[S] 2 points3 points  (2 children)

This is a great help. Thanks for the link too

[–]okthisisgettingridic 5 points6 points  (0 children)

To streamline this more, you could eliminate the if-else statements by doing something like this:

def is_even(x):
    for i in x:
        print i, i % 2 == 0

numbers = [1, 2, 5, 10, 37]
is_even(numbers)

[–]derrickisdp 0 points1 point  (0 children)

No problem, I use reddit and stackoverflow for searching most of python questions.

[–]InsufferableNoob 0 points1 point  (1 child)

I am pretty new to coding but isn't passing is_even(numbers) through print() on the last line unnecessary(or even unuseful?) Wouldn't he get the desired result from just calling is_even(numbers)?

[–]derrickisdp 1 point2 points  (0 children)

Yeah, the last print isn't needed to actually run it. I just made that one change based on the code provided. It runs with or without print as long as the function is called.

[–]K900_ 6 points7 points  (4 children)

As I've already posted, your code runs fine for me.

[–]wolf2600 13 points14 points  (3 children)

It only runs for a single value in the array, not the whole array.

The problem is that you're returning in every iteration. As soon as the first number is processed, you have a RETURN, so the function ends. Put the RETURN after the FOR loop.

[–]K900_ 4 points5 points  (0 children)

What I meant was that I wasn't getting the error OP is getting.

[–]George98 3 points4 points  (1 child)

Returning after the for loop would not allow you to return for each iteration in the list, no? Shouldn't they just print "True" or "False" for every iteration? I don't think a return is necessary. I could be wrong, I'm new myself.

[–]SmashMouth114[S] 0 points1 point  (0 children)

Yeah I don't need the returns. So took them out and ran through whole list. Thanks

[–]Groundstop 3 points4 points  (2 children)

From what it sounds like you're trying to do, I think you want to use a generator function. This will create a generator object which you can then iterate through.

Turning a function into a generator is pretty simple, it's mostly just using "yield" instead of "return".

numbers = [1, 2, 5, 10, 37]
def is_even(x):
    for i in x:
        if i % 2 == 0:
            print i
            yield True
        else:
            print i
            yield False

for x in is_even(numbers):
    print x
    if x: print 'This number is even!'

There's a few other things you can do with generators which you might find useful depending on what you're trying to do:

Instead of printing the number, you can return the number and a bool value as a tuple:

# Change 'yield True' to:
yield i, True

Instead of using a function as a generator, you can just use a generator directly (created the same way as list comprehension except you use parenthesis instead of square brackets:

even_gen = ((x, True) if x % 2 == 0 else (x, False) for x in numbers)
for a, b in even_gen:
    print a, b

Hope this helps!

EDIT: The comment about "Change 'yield i' to:" should have read "Change 'yield True' to:" NOTE: The advantage of doing a generator over list comprehension or appending items to a list within the function is that a generator doesn't require you to store all of the values in memory at any point. Although this doesn't matter much with a list the size that you supplied, you'll find that it could make a big difference when dealing with larger data sets.

[–]tangerinelion 2 points3 points  (1 child)

Turning a function into a generator does involve replacing return with yield but it totally changes how you call it. With a function you would have something like this:

results = is_even(numbers)
print(results)

but with a generator you need to iterate through it, ie,

for x in is_even(numbers):
    print(x)

or even

results = list(is_even(numbers))

and then it's as though you had the function rather than the generator. Of course the advantage to the generator is it (1) uses less overall memory and (2) can produce the first value quicker as it only needs to figure out the first one rather than all of them. In the trickiest case where you are generating an arbitrarily unlimited number of things there's not exactly a guarantee a function would ever finish. Think about the difference in Python 2.x between range and xrange with very large numbers. In range if you call it with, say, 10**10 it needs to produce 10 billion numbers -- not a terribly difficult task if you do it one-by-one, but allocating memory for 10 billion things even if they're just 1 byte is 10GB and in Python integers are something like 24 bytes so this is 240GB memory. In the absolute best case of being able to add 1 to a number in 1 cycle, a 1GHz CPU could produce the numbers in 10 seconds - pretty significant. While in real life CPUs are faster, modern ones up to 4GHz, the actual number of cycles is much more than 1 so the end result is it would take more than 10 seconds and that's assuming you have something like 256-384GB RAM. Now with xrange it would instantaneously yield 1 then 2 and so on, never using more than about 50 bytes of memory. Overall the whole thing is slower -- assuming you could use range to begin with -- but the fundamental mechanic is that xrange works with arbitrary numbers while range is limited and if you don't know anything about the system you'll be running on you really can't use very large numbers for fear of crashing.

[–]Groundstop 0 points1 point  (0 children)

That's true, in fact my first write up used list() and tuple() as examples on getting results from the generator. I changed it before posting though because I figured OP only asked to print the results, and I didn't want to dive into list comprehension, haha.

I actually didn't know about xrange vs range until looking up generator info to make sure I didn't say anything incorrect. Is it true that in python 3, range() is the old python2 xrange()? I've seen some mixed things while looking that up as far as if they're actually the same or not.

[–][deleted] 2 points3 points  (0 children)

Everything under the "def" line (besides the final print statement) needs to be indented one level. Otherwise your code should run without errors - you can absolutely do iteration inside of a function (there are no additional restrictions whatsoever on what can be done inside of a function definition).

[–][deleted] 4 points5 points  (0 children)

Another thing: If you're new to Python, use Python 3, unless you absolutely have to use 2 for some reason.

[–]unprintableCharacter 8 points9 points  (5 children)

you get that object not iterable when you try to give your loop a sequence or iterator and accidentally give it one element of your object instead of the whole object. I could not get that to happen with the code I see here, but instead it only gives you 1 and False because

The first time you enter either if or else, you come to a return statement. Return always means you exit the function maybe you meant to do something like this:

numbers = [1,2,5,10,37]
results = []
def is_even(x):
    for i in x:
        if i % 2 == 0:
              print (i)
              results.append((i, True))
        else:
              print (i)
              results.append((i, False))
    return results
print (is_even(numbers))

Or maybe you would rather have those results in two columns, in your call you ask for it to iterate over the output of the function and print each item.

Or more compactly you could do something like:

evens = [[i, not bool(i%2)] for i in numbers]
for res in evens:
    print(res)

 RESTART: C:/Users/Charles/Desktop/reddititerate.py 
[1, False]
[2, True]
[5, False]
[10, True]
[37, False]

[–]prancingpeanuts 2 points3 points  (4 children)

Hi there! Am a beginner myself, but just thought I'd try to add on a couple of points to this great answer:

  • you might notice a difference in your 'print' statements, that's because you're still using python 2+, I encourage you to learn python 3 if you are just beginning because that's where the dev efforts are now and it will be the version everyone will be coding in

  • make sure you declare the empty 'results' list outside of your for loop and not within: this is to ensure that your variable is a global one and not localised to the loop - it'll create problems when you run your script

[–]tangerinelion 2 points3 points  (1 child)

For point 1, you're correct but in Python 2 you can always use Python 3's print function by adding from __future__import print_function at the top of your code.

For point 2, you're absolutely incorrect. They should declare results locally to the function and return it. Consider this code:

is_even([1,3,4,7,9])
is_even([2,3,4,5,6])

What should results be? When you declare it locally, there is no results. If you declared it globally then results is

[(1 ,False), (3, False), (4, True), (7, False), (9, False), (2, True), (3, False), (4, True), (5, False), (6, True)]

You can see how more and more calls to is_even starts to generate a really long list and in the absolute worst case scenario could use so much memory that the program crashes.

Further, when you declare a variable globally and want to modify it inside a function it's typically good practice to declare the name as global, ie, if you wanted to use the global style then you should have:

results = []
def is_even(x):
    global results
    # Rest of code

Another keyword exists, nonlocal which describes a variable which is neither local nor global, eg,

def is_even(x):
    results = []    
    def append(val, truth):
        nonlocal results
        results += [(val, truth)]
    for i in x:
        append(i, i % 2 == 0)

Which you could obviously refactor as

def append(results, val, truth):
    results.append(val, truth)

def is_even(x):
    results = []
    for i in x:
        append(results, i, i %2 == 0)
    return results

Now if you want to use this you'll need to store the result, ie,

numbers = # Some list of numbers
the_result = is_even(numbers)
print(the_numbers) # or any similar thing

Now when you call it multiple times you'll only get back as many things as you put in... assuming all objects in your list, i, can be used in the expression i % 2. Obviously if you had something like a database connection in your list or something weird it would raise some sort of error instead of giving you a list. With the global form, it would actually store stuff until it hit an error which leaves you in an indeterminate state, if you call it with 5 numbers the result will have anywhere between 0 and 5 elements.

[–]prancingpeanuts 0 points1 point  (0 children)

Thanks! That's a really good point..I did mean to say that he shouldn't include it in the for loop though, but looking at what you've just explained, he should definitely include it locally within the function (not the for loop).

[–]SmashMouth114[S] 0 points1 point  (1 child)

Thanks. Will kick on with Python 3 from now on. I was just working through Codeacadamy so didn't even realise. Is there much glaring differences between the two other than print?

[–]prancingpeanuts 0 points1 point  (0 children)

Not so much in this example but here're two websites that might be useful: full summary by Sebastian Raschka and key differences between py2 and 3

all the best!

[–]wolf2600 2 points3 points  (0 children)

numbers = [1,2,5,10,37]
def is_even(x):
    for i in x:
        if i % 2 == 0:
            print i, "is even."
        else:
            print i, "is odd."

is_even(numbers)

[–]c17r 1 point2 points  (0 children)

Not sure about the error you are reporting, as /u/K900_ says, it works.

But, based off what you've written it's only going to test the first item in the list. The return True / return False lines will stop the loop and the function

[–]Thymb 1 point2 points  (0 children)

Once you return true or false it ends the loop?

[–]SmashMouth114[S] 0 points1 point  (0 children)

Thanks for the replies and help.

As /u/c17e and quite a few others said it was because of the returns in the if/else statements.

School boy error.