3

My instructions in a codecademy project are to

Define a function called purify that takes in a list of numbers, removes all odd numbers in the list, and returns the result. For example, purify([1,2,3]) should return [2]. Do not directly modify the list you are given as input; instead, return a new list with only the even numbers.

The code I have come up with is:

def purify(numbers):

pure = numbers

for num in pure:
    if num % 2 != 0:
        pure = pure.remove(num)

return pure

And the error is:

Oops, try again. Your function crashed on [1] as input because your function throws a "'NoneType' object is not iterable" error.

As I've come to understand it, this means something in my code is being returned as "None". Or there is no data there. I can't seem to find what's wrong with this short and simple code, unless it's in my if statement. Thanks in advance.

So I made the edit within the code to remove "pure = pure.remove(num)" and that solved the none issue. However, when running the code it still fails the input of [4,5,5,4] and returns [4,5,4].

New Code:

def purify(numbers):

    pure = numbers

    for num in pure:
        if num % 2 != 0:
            pure.remove(num)

    return pure
7
  • 2
    Your code makes exactly the same mistake the same classmate I linked to earlier did (maybe you should have read it?); don't modify lists while iterating over them. Also, list.remove is in-place, so will return None. Also, pure = numbers does not create a copy, so you aren't meeting the specification. Commented Aug 15, 2014 at 21:24
  • Make sure to post valid code that accurately reproduces the problem. Trivially, the indenting is incorrect and the presented code will not parse. Commented Aug 15, 2014 at 21:24
  • list.remove return None. It modifies the list instead. Also, do not modify the list while you are iterating over it Commented Aug 15, 2014 at 21:24
  • So if pure = numbers does not make a copy, and I can't modify a list while iterating over it, what are my options to not edit the original list and return a clean list? Commented Aug 15, 2014 at 21:38
  • 1
    For the love of everything, read the question I keep providing a link to! There are several answers there that aren't unique to strings and vowels, and will work happily with lists of even and odd numbers. To copy a list, do e.g. pure = numbers[:]. Consider adding to an empty list instead of removing from a full one. Use filter or a list comprehension. Commented Aug 15, 2014 at 21:45

4 Answers 4

8

The first problem is that you change the list while iterating over it. DO NOT change lists while you are iterating over them. You will miss out on some of the values in the loop.

The second problem is that list.remove acts in-place and returns None. Thus, when you do pure = pure.remove(num), you set pure to None, which is no longer iterable, which in turn is what causes the error. Instead, you can filter the list as follows

def purify(numbers):
    return [num for num in numbers if num % 2 == 0]
Sign up to request clarification or add additional context in comments.

2 Comments

This is great. This is what I was looking for. Is this the filter function or list comprehension? I still don't grasp list comprehension which is why I ask. Thanks again!
This is a list comprehension. It adds each item num from numbers to the new list (num for num in numbers), but only iff (that's a word) num is even (if num % 2 == 0).
2

Well that error means that python is trying to iterate over a None object.

The only iteration in your code is your for loop, so pure must be the None.

Also, don't forget to indent properly:

def purify(numbers):

    pure = numbers

    for num in pure:
        if num % 2 != 0:
            pure = pure.remove(num)

    return pure

So pure is either being defined as None when you set it equal to numbers or it's being defined when you assign it from pure.remove(num). When you look up the documentation for remove(num), you see that it operates in-place, so it doesn't return anything useful (None usually). What you want to do it remove the pure = part in the for loop. You might notice that you end up skipping elements in your loop, but that would a separate problem with this piece of code (modifying something you're iterating over).

Comments

0

I have no idea what pure's type is but it seems that it's a mutable object. pure.remove updates pure in place, and therefore returns None. You shouldn't set it into pure. Moreover, you shouldn't modify objects you iterate over during the iteration itself.

EDIT: The previous code snippet I put here was incorrect, as mentioned in the comments. I suggest you pick one of the methods mentioned in the other answers. If you're really interested in maintaining the general structure of your current solution, here is a workaround that uses the copy module:

import copy

def purify(numbers):
    pure = copy.copy(numbers) # a shallow copy
    for num in numbers:
        if num % 2 != 0:
            pure.remove(num)

    return pure

Note that numbers's class should implement the __copy__ method for this to work. You've mentioned in your comments above that numbers is a list, so the built-in implementation works for you. However, for a list you can simply do the following:

pure = numbers[:]

2 Comments

You can also copy using pure = numbers[:] instead of using copy
Yeah, I just now noticed that numbers is a list. Thanks :-)
-2
def purify(numbers):
    sequence = []     //starting with a an empty 
    for f in sequence:
        if f%2 -1:    //filtering out odd numbers,alternative to f%2 ==0
            sequence.append(f) //append each even number to the empty list
    return sequence

N/B:starting with an empty list ensures list is not modified

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.