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:
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)
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.
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,
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)
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With