for_loop.py
for i in [0, 1, 2, 3, 4]:
print(i)
When you run
% python for_loop.py
0
1
2
3
4
for i in
I want to know how the thing behind is used.
(In the case of the above example, it seems that the elements of ``` [0, 1, 2, 3, 4]` `` are extracted in order.)
Let's see how it is hit with reference to the runtime error
duck.py
class Duck(object):
pass
if __name__ == '__main__':
for i in Duck():
print(i)
When I run it, I get angry if it is not iterable
% python duck.py
Traceback (most recent call last):
File "duck.py", line 6, in <module>
for i in Duck():
TypeError: 'Duck' object is not iterable
`__ iter__ ()`
methodI was told to implement it, so I will implement it. But just return an empty object
duck.py
class DuckIter(object):
def __init__(self):
pass
class Duck(object):
def __iter__(self):
return DuckIter()
if __name__ == '__main__':
for i in Duck():
print(i)
The error has changed (one step forward!)
% python duck.py
Traceback (most recent call last):
File "duck.py", line 12, in <module>
for i in Duck():
TypeError: iter() returned non-iterator of type 'DuckIter'
next ()
`` methodTry to squeal three times.
duck.py
class DuckIter(object):
def __init__(self):
self._count = 3
def next(self):
if self._count > 0:
self._count -= 1
return "quack"
raise StopIteration()
class Duck(object):
def __iter__(self):
return DuckIter()
if __name__ == '__main__':
for i in Duck():
print(i)
No more errors when run
% python duck.py
quack
quack
quack
The duck rang!
If it walks like a duck and quacks like a duck, it must be a duck https://ja.wikipedia.org/wiki/ダック・タイピング
The object itself determines what the object can do (Regardless of what inheritance they have)
In the case of the previous example
`__ iter__ ()`
method.
next ()
`` method.This allowed us to turn the for loop:
for i in Duck():
print(i)
This notation is roughly the same as below
iter = Duck().__iter__()
while True:
try:
i = iter.next()
print(i)
except StopIteration:
break
In other words, the processing flow of the for loop is
Let's create an object with iterator in reverse order from list
>>> lst = [0, 1, 2, 3, 4]
>>> rev = RevList(lst)
>>> for r in rev:
... print(r)
...
4
3
2
1
0
Tip:
`` next () `` method" with ``` __iter__ ()
```next ()`
returns from the end of the original listclass RevListIter(object):
def __init__(self, lst):
self._orig = lst
self._i = len(lst)
def next(self):
if self._i > 0:
self._i -= 1
return self._orig[self._i]
raise StopIteration()
class RevList(object):
def __init__(self, lst):
self._orig = lst
def __iter__(self):
return RevListIter(self._orig)
if __name__ == '__main__':
lst = [0, 1, 2, 3, 4]
rev = RevList(lst)
for r in rev:
print(r)
class RevList(object):
def __init__(self, lst):
self._orig = lst
def __iter__(self):
return self._orig[::-1].__iter__()
if __name__ == '__main__':
lst = [0, 1, 2, 3, 4]
rev = RevList(lst)
for r in rev:
print(r)
Let's create an iterator that squares each element of a list of integers
>>> lst = [0, 1, 2, 3, 4]
>>>for i in something(lst):
... print(i)
...
0
1
4
9
16
>>> lst = [0, 1, 2, 3, 4]
>>> for i in [x*x for x in lst]:
... print(i)
...
0
1
4
9
16
>>> for i in (x*x for x in lst):
... print(i)
...
0
1
4
9
16
Both are solutions. Let's see the difference between the two.
notation
[f(x) for x in lst]
Sample code
list_comprehension.py
def f(x):
print("%d*%d" % (x, x))
return x*x
if __name__ == '__main__':
lst = [0, 1, 2, 3, 4]
x = [f(x) for x in lst]
print(type(x))
for i in x:
print(i)
Execution result
% python list_comprehension.py
0*0
1*1
2*2
3*3
4*4
<type 'list'>
0
1
4
9
16
notation
(f(x) for x in lst)
Sample code
generator_expression.py
def f(x):
print("%d*%d" % (x, x))
return x*x
if __name__ == '__main__':
lst = [0, 1, 2, 3, 4]
x = (f(x) for x in lst)
print(type(x))
for i in x:
print(i)
Execution result
% python generator_expression.py
<type 'generator'>
0*0
0
1*1
1
2*2
4
3*3
9
4*4
16
__iter__ ()` ``,
next ()` ``, iterable is completed.Recommended Posts