Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does iter() work, it's giving "TypeError: iter(v, w): v must be callable"

What is the problem with this code?

l = [1,2,3,4,5,6]
for val in iter(l, 4):
    print (val)

It returns

TypeError: iter(v, w): v must be callable

Why does callable(list) return True but callable(l) does not?

EDIT What method should be preferred here:

  1. manual breaks
  2. hundred others
like image 998
new-kid Avatar asked Nov 08 '13 08:11

new-kid


5 Answers

When called with two arguments, iter takes a callable and a sentinel value. It's behavior is like it was implemented so:

def iter2args(f, sentinel):
    value = f()
    while value != sentinel:
        yield value
        value = f()

What gets passed in as f must be callable, which just means that you can call it like a function. The list builtin is a type object, which you use to create new list instances, by calling it like a function:

>>> list('abcde')
['a', 'b', 'c', 'd', 'e']

The list l you passed in is an existing list instance, which can't be used like a function:

>>> l = [1,2,3,4,5,6]
>>> l(3)
Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    l(3)
TypeError: 'list' object is not callable

Thus, there is a large and important difference between the list type object and list instances, which shows up when using with iter.

To iterate through a list until a sentinel is reached, you can use itertools.takewhile:

import itertools
for val in itertools.takewhile(l, lambda x: x!= 4):
    print(val) 
like image 160
Michael J. Barber Avatar answered Oct 26 '22 23:10

Michael J. Barber


From iter help:

iter(...)
iter(collection) -> iterator
iter(callable, sentinel) -> iterator

Get an iterator from an object.  In the first form, the argument must
supply its own iterator, or be a sequence.
In the second form, the callable is called until it returns the sentinel.

You are mixing two variants of iter function. First one accepts collections, second accepts two arguments - function and sentinel value. You're trying to pass collection and sentinel value, which is wrong.

Short note: you can get a lot of interesting info from python's built-in help function. Simply type in python's console help(iter) and you'll get documentation on it.

Why does callabe(list) return true but callable(l) does not?

Because list is function which returns new list object. Function is callable (that's what function does - it gets called), while instance which this function returns - new list object - is not.

like image 28
aga Avatar answered Oct 27 '22 01:10

aga


It has to do with the second value being pass (a so called sentinel value), this ensures that the object being iterated over is a callable ie. a function. So for every iteration that iter()does it calls __next__() on the object being passed.

iter() has two distinct behaviors,

  • without a sentinel value
  • with a sentinel value

The example in the documentation is great for understanding it

with open("mydata.txt") as fp:
    for line in iter(fp.readline, "STOP"): #fp.readline is a function here.
        process_line(line)
like image 21
Henrik Andersson Avatar answered Oct 26 '22 23:10

Henrik Andersson


Have a look at docs: http://docs.python.org/2/library/functions.html#iter

When second argument in iter is present then first argument is treated very differently. It is supposed to be a function which is called in each step. If it returns sentinel (i.e. the second argument), then the iteration stops. For example:

l=[1,2,3,4,5,6]

index = -1
def fn():
    global index
    index += 1
    return l[index]

for val in iter(fn, 4):
    print (val)

EDIT: If you want to just loop over a list and stop when you see a sentinel, then I recommend doing simply this:

for val in l:
    # main body
    if val == 4:
        break
like image 43
freakish Avatar answered Oct 27 '22 00:10

freakish


Remember that classes are objects in Python.

>>> callable(list)
True

Means that list itself is callable, rather than instances of it being callable. As you've seen, they aren't:

>>> callable([])
False

In fact, all classes in Python are callable - if they don't have literals like list, this is the usual way to instantiate them. Consider:

def MyClass:
     pass

a = MyClass()

The last line calls the MyClass class object, which creates an instance - so, MyClass must be callable. But you wouldn't expect that instance to be callable, since MyClass itself doesn't define an __call__.

On the other hand, the class of MyClass (ie, its metaclass, type) does:

>>> type.__call__
<slot wrapper '__call__' of 'type' objects>

which is what makes MyClass callable.

like image 32
lvc Avatar answered Oct 27 '22 01:10

lvc