About
program ape a thoughtful, lifelong learning practitioners, is currently in a start-up team any team lead, technology stack involves Android, Python, Java, and Go, this is the main technology stack our team.
GitHub: https://github.com/hylinux1024
micro-channel public number: Lifetime developer (angrycode)
In Python
the iterable ( Iterable
), the iterator ( Iterator
) and generator ( Generator
) these concepts are often used, these few beginner is often confused with the concept, it is time to put a few concepts to figure out.
0x00 iterable (Iterable)
Simply put, an object (which in Python everything is an object) as long as the realization of the long realized the __iter__()
method, then a isinstance()
check is a function of Iterable
the object;
E.g
class IterObj:
def __iter__(self):
# 这里简单地返回自身
# 但实际情况可能不会这么写
# 而是通过内置的可迭代对象来实现
# 下文的列子中将会展示
return self
The above definition of a class IterObj
and implements the __iter__()
method, this is a can iteration (the Iterable) Object
it = IterObj()
print(isinstance(it, Iterable)) # true
print(isinstance(it, Iterator)) # false
print(isinstance(it, Generator)) # false
Remember this class, we will see below this class definition.
Common iterables
In Python
which common iterable have it?
- Set or sequence type (e.g.
list
,tuple
,set
,dict
,str
) - File object
- Defined in the class
__iter__()
method objects may be considered asIterable
an object, but the iterative custom objects to be able tofor
use the correct cycle, it is necessary to ensure the__iter__()
implementation must be correct (i.e., by the built-initer()
turn a function ofIterator
the object. AboutIterator
Hereinafter Description will be here to leave a pit, just remember thatiter()
the function is the ability to turn into a iterable iterator object, then infor
use)
- Achieved if only implemented in the class
__getitem__()
object can beiter()
converted to the iterator functions but not in themselves an object of iterations. So when an object is able tofor
run in cycles, but not necessarilyIterable
object.
About 1,2 point we can verify the following
print(isinstance([], Iterable)) # true list 是可迭代的
print(isinstance({}, Iterable)) # true 字典是可迭代的
print(isinstance((), Iterable)) # true 元组是可迭代的
print(isinstance(set(), Iterable)) # true set是可迭代的
print(isinstance('', Iterable)) # true 字符串是可迭代的
currPath = os.path.dirname(os.path.abspath(__file__))
with open(currPath+'/model.py') as file:
print(isinstance(file, Iterable)) # true
We look at point 3 ,
print(hasattr([], "__iter__")) # true
print(hasattr({}, "__iter__")) # true
print(hasattr((), "__iter__")) # true
print(hasattr('', "__iter__")) # true
These built-in set or sequence object has __iter__
properties that they have achieved the same name as the method. But this iterables want to for
be in use cycle, then it should be a built-in iter()
function calls and converted into Iterator
objects.
For example, we look at the built-in iterables
print(iter([])) # <list_iterator object at 0x110243f28>
print(iter({})) # <dict_keyiterator object at 0x110234408>
print(iter(())) # <tuple_iterator object at 0x110243f28>
print(iter('')) # <str_iterator object at 0x110243f28>
They are turned into respective corresponding iterator ( Iterator
) object.
Now go back and look at the beginning of the definition of IterObj
the class
class IterObj:
def __iter__(self):
return self
it = IterObj()
print(iter(it))
We use the iter()
function, this time Jiangzai console print out the following information:
Traceback (most recent call last):
File "/Users/mac/PycharmProjects/iterable_iterator_generator.py", line 71, in <module>
print(iter(it))
TypeError: iter() returned non-iterator of type 'IterObj'
The type of error occurred, meaning that iter()
the function can not be transferred 'non iterator' into iterator type.
Then how can one be iterative ( Iterable
) object into a iterator ( Iterator
) object?
We'll revise the IterObj
definition of the class
class IterObj:
def __init__(self):
self.a = [3, 5, 7, 11, 13, 17, 19]
def __iter__(self):
return iter(self.a)
We define a constructor named in a
the list, and also implements __iter__()
the method.
Modified class can be iter()
invoked function, i.e. may be in for
use cycle
it = IterObj()
print(isinstance(it, Iterable)) # true
print(isinstance(it, Iterator)) # false
print(isinstance(it, Generator)) # false
print(iter(it)) # <list_iterator object at 0x102007278>
for i in it:
print(i) # 将打印3、5、7、11、13、17、19元素
Thus when defining an iterator object, we pay close attention to __iter__()
the internal process logic implemented, in general, are known by a number of iterations may be objects (e.g., the above-mentioned set, sequence, or other files defined correctly iterable) to assist us to achieve
About point 4 means that the described iter()
functions can be achieved a __getitem__()
target converted into the method iterator object may be in for
use cycle, but if the isinstance()
time detecting method, it is not an iterator object.
class IterObj:
def __init__(self):
self.a = [3, 5, 7, 11, 13, 17, 19]
def __getitem__(self, i):
return self.a[i]
it = IterObj()
print(isinstance(it, Iterable)) # false
print(isinstance(it, Iterator)) # false
print(isinstance(it, Generator)) false
print(hasattr(it, "__iter__")) # false
print(iter(it)) # <iterator object at 0x10b231278>
for i in it:
print(i) # 将打印出3、5、7、11、13、17、19
This example illustrates the can in for
the object in use, it is not necessarily iterables.
Now we make a summary:
- An iteration object is to achieve a
__iter__()
method of the object - It is to be in
for
use cycle, it must meet theiter()
call (ie, calling this function will not be wrong, can turn into a properIterator
objects) - It can be assisted to achieve iterables our custom known by iterable.
- Object implements a
__getitem__()
method can beiter()
converted into a functionIterator
that can befor
used in the loop, but it is not an iterator object (available isinstance detection method ())
0x01 iterator (Iterator)
Many places have mentioned above Iterator
, now we have to fill the pit.
When we can understand the concept of iterations for the iterator it is better understood.
An object implements __iter__()
and __next__()
methods, then it is an iterator object. E.g
class IterObj:
def __init__(self):
self.a = [3, 5, 7, 11, 13, 17, 19]
self.n = len(self.a)
self.i = 0
def __iter__(self):
return iter(self.a)
def __next__(self):
while self.i < self.n:
v = self.a[self.i]
self.i += 1
return v
else:
self.i = 0
raise StopIteration()
In the IterObj
definition of a list, constructor a
, length of the list n
, index i
.
it = IterObj()
print(isinstance(it, Iterable)) # true
print(isinstance(it, Iterator)) # true
print(isinstance(it, Generator)) # false
print(hasattr(it, "__iter__")) # true
print(hasattr(it, "__next__")) # true
We can find the above-mentioned
collections and objects are iterative sequence but not the iterator
print(isinstance([], Iterator)) # false
print(isinstance({}, Iterator)) # false
print(isinstance((), Iterator)) # false
print(isinstance(set(), Iterator)) # false
print(isinstance('', Iterator)) # false
The file object is an iterator
currPath = os.path.dirname(os.path.abspath(__file__))
with open(currPath+'/model.py') as file:
print(isinstance(file, Iterator)) # true
An iterator ( Iterator
) objects can not only for
use cycle, built-in functions can also next()
be called function. E.g
it = IterObj()
next(it) # 3
next(it) # 5
0x02 generator (Generator)
Now let's look at what is the builder?
A generator is both iterative iterators also
Generator defines two ways:
- List Builder
- Using
yield
the definition of the function generator
Look at the Case 1
g = (x * 2 for x in range(10)) # 0~18的偶数生成器
print(isinstance(g, Iterable)) # true
print(isinstance(g, Iterator)) # true
print(isinstance(g, Generator)) # true
print(hasattr(g, "__iter__")) # true
print(hasattr(g, "__next__")) # true
print(next(g)) # 0
print(next(g)) # 2
List Builder may not need to consume a lot of memory to generate a huge list, will only be calculated when needed the data.
Look Case 2
def gen():
for i in range(10):
yield i
This yield
effect is equivalent to return
, is the order of this function returns the [0,10)
natural number can be produced by next()
or for
loop to iterate.
When the program encounters yield
keyword, the generator function returns, until once again perform the next()
function, it will continue from the last execution point function returns, that is, yield
save the information on the location of the function execution, variables, and so on exit, when executed again, on this yield
continue down the exit place.
In Python
utilizing these features of the generator may be implemented coroutine. Coroutine can be understood as a lightweight thread, thread it with respect to the treatment of high concurrency scenarios has many advantages.
Here with a look of realization coroutine producer - consumer model
def producer(c):
n = 0
while n < 5:
n += 1
print('producer {}'.format(n))
r = c.send(n)
print('consumer return {}'.format(r))
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('consumer {} '.format(n))
r = 'ok'
if __name__ == '__main__':
c = consumer()
next(c) # 启动consumer
producer(c)
This code performs the following effects
producer 1
consumer 1
producer return ok
producer 2
consumer 2
producer return ok
producer 3
consumer 3
producer return ok
Coroutine achieved CPU
effect switching between the two functions to achieve concurrency.