How does iter() work, it's giving "TypeError: iter(v, w): v must be callable"
From iter
help:
iter(...)
iter(collection) -> iterator
iter(callable, sentinel) -> iteratorGet 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.
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)
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)