Article From:https://www.cnblogs.com/tootooman/p/9018215.html

1、List generation

# Common generation list
ab=[]
for x in range(10):
    ab.append(x*x)
print(ab)

# List expression
a=[x*x for x in range(10)] # This is called list generation, also called open programming
'''
1:Pretaking elements2: take the extracted elements to a x*x3: put the finished elements in the list in turnPrint (a)'''

egg=[x for x in range(100) if x<50]    # If x is less than 50, add a list of egg
print(egg)

Shortcomings:If the object that can be iterated is very large, it will put all the iterated content into memory processing and take up the memory.

2、Generator Expressions

#Generator Expressions
egg = (x for x in range(100) if x < 50) # This is called generator expression, and the difference from list generation is using parentheses.

print(egg)  # <generator object <genexpr> at 0x000001FCDB352E60>  Generator object

# If you want to take the value through the for cycle, or next method.
for i in egg:
    print(i) 

print(next(egg))
print(next(egg))
print(next(egg))
print(next(egg))

'''
The difference from the list generationList generation has index, flexible value, and can get length.The generator expression saves the memory, with one fetch, one can not get the length, and no index.'''

 

3、iterator

'''
The iterator protocol satisfies two conditions1: objects can be converted to iterator by __iter__ method, or ITER (obj).2: objects can be valued by __next__ or next (obj).'''

l=[1,2,3,5]  # A list is an iterated object, not an iterator. There is a ITER method.

d=iter(l)  # Or l.__iter__ (), convert the list to an iterator by ITER function or __iter__ () method.
print(d)  # <list_iterator object at 0x0000000000B16B38>


# Advantage:
'''
1:Iterators provide a way of indexing that does not depend on index, so that iterated objects (dictionaries, collections, files) without index can be traversed.2: iterator compared with list, iterator is inert computing, saving more memory, what is inert computing, list can iterate object, and iterator ratio.We can know the length len method of the iterated object, but we can not know the length of the iterator, and the iterator takes only one data per next.'''

# Shortcomings:
'''
Disposable, only after the value, not inverted value.'''

Take the contents of the iterator

print(d.__length_hint__())  # Get the length of the iterator element
d.__setstate__(2)   # Setting the start of the iterator index value
print(next(d))  # Use the next method to take the values in the iterator object
print(next(d))
print(next(d))  # Wrong, why, look at while and for below


while True:
    try:
        print(next(d))      # The content in the loop iterator
    except StopIteration:   # To catch StopIteration's mistakes
        break   # Once caught, quit


for i in d:
    print(i)
'''
for There were three things in the circle.1: invoke the __iter__ method of the iterated object (d) to return an iterator object.2: continue to call the iterator object's next method to get the value.3: dealing with stopiteration anomalies, principle andThe while above is almost the same'''


from collections import Iterator,Iterable
print(isinstance(l,Iterable))  Determine whether it is an Iterable objectIterator iteratorIterable can be iterated# Format isinstance (object, type)
isinstanceMethod: to determine whether an object is a specified type is to return to True or not to return to False.

4、generator

Note: generators are iterators, and iterators are not necessarily generators.

# Create a generator:

a = (x*2 for x in range(5))    # Creating a generator through a generator expression


# There is a yield keyword in the function, which means that the function is a generator, and its internal function is to make the function iterator.
def foo():
    print('ok')
    yield 1   # Return value, similar to return, return to next ()
    print('ok2')
    yield 2   # Return value, similar to return

g=foo()  # foo() Return a generator object
print(g)  #<generator object foo at 0x000000000083A518>
next(g) # The OK is displayed: the return value is 1, the generator is also an iterator, and is selected by next method.
next(g) # Display is ok2: return value 2
# a=next(g)   # 1  ,The screen will output OK
# b=next(g)   # 2  ,The screen will output ok2
# print(a,b)


for Cycle processfor i in foo(): 
    while True:
        i=next(foo()) #Next (foo ()) is first executed to return to print (OK), then the value of yield is returned to I, print (I) =1.
ok
1
ok2
2

 

# A generator is an Iterable object (Iterable)

The generator automatically implements the iterator protocol

for i in a: 
    print(i)
# for A next method call to the a object is made, and a value is taken, second values are taken, the first value has no variable reference, and the memory garbage is reclaimed to save memory.

# What is the difference between the generator yield and the function return?

returnOnce you return only once, the function is completely ended, and yield can return multiple values.

 

# yieldWhat the hell did you do:

yield Encapsulate the __iter__ and __next__ methods inside the function and turn them into generator –> iterator.

Return value with return can be returned once, and yield returns multiple times.

The state of the function is pause and the next runtime is saved by yield.

 

send Method

def bar():
    print('ok')
    count=yield 1
    print(count)
    print('ok2')
    yield 2
b=bar()  #Generating a generator object
ret=b.send(None)  #b.send(None)=next(b)  Before the first send, if there is no next, you can only pass a None and return the value of the yield; it is given to RET, or next (b) is executed, and you can also write an initialer's decorator.
print(ret)  # ret The value of yield is: 1
ret2=b.send('eee') #Assign EEE to count and return the value of count EEE
print(ret2)

send() The difference from next ()

1、If yield in the function is an expression form, then next (E) must be first, so that an adornment can be made for the generator so that it doesn’t need to be next every time.
2、The common thing between the two is that the function can keep the function running at the last pause position, and the difference is that send passes a value to yield when it triggers the next code execution.
3、send Many times are worth passing in the form of Yuan Zu.

 

An example of a generator

Faye Bona Che series

# def fib(max):
#     n,before,after=0,0,1
#     while n < max:
#         print(before)
#         before,after=after,before+after
#         n+=1
#
# fib(2)


def fiber(max):
    n,before,after=0,0,1
    while n<max:
        yield before
        before,after=after,before+after
        n+=1
g=fiber(8)   # Generator object
# print(g)
# print(next(g))   # Return the yield value of the generator object
# print(next(g))

View Code

 

Generator practice

Write a log calling method through the generator to support the following functions

Output logs to the screen based on instructions

Output logs to files based on instructions

To the file &amp at the same time; the screen output log

The above log format is as follows

2017-10-19 22:07:38 [1] test log db backup 3

2017-10-19 22:07:40 [2] user alex login success

#Note: [1], [2] refers to several calls from the log method, and a log is output at each call.

def init(func):
    def warpper(*args, **kwargs):
        res = func(*args, **kwargs)
        next(res)
        return res
    return warpper


@init
def logger(filename, channel='terminal'):

    count = 1

    while 1:

        c = yield 1
        current_time = time.strftime('%Y-%m-%d %H:%M:%S')
        info = '%s [%s] %s' % (current_time, count, c,)

        if channel == 'terminal':
            print(info)
        elif channel == 'file':
            with open('example.ini', 'a', encoding='utf8') as f:
                f.write('\n%s' % (info,))
        elif channel == 'both':
            print(info)
            with open('example.ini', 'a', encoding='utf8') as f:
                f.write('\n%s' % (info,))
        count += 1


lo = logger('abc', channel='both')
next(lo)
lo.send('aaa')
time.sleep(2)
lo.send('ccc')

View Code

Analog Linux tail command

#!/usr/local/python3.5.2/bin/python3.5
def tail_f(file_path):
    import time
    with open(file_path,'r') as f:
        f.seek(0,2)   # The cursor is always at the end of the tail
        while True:
            for line in f:
                if not line:  # Stop if it's empty
                   time.sleep(0.3)
                   continue
                else:
                    yield line.strip()

g=tail_f('a.txt')
for i in g:
    print(i)

View Code

Tail + grep command for analog Linux

def tail_f(file_path):
    import time
    with open(file_path,'r') as f:
        f.seek(0,2)
        while True:
            for line in f:
                if not line:
                   time.sleep(0.3)
                   continue
                else:
                    yield line


def grep(partten,lines):
    for line in lines:
        if partten in line:
            yield line

g1=tail_f('a.txt')
g2=grep('error',g1)
for i in g2:
    print(i.strip())

View Code

.

Link of this Article: Python’s iterator and generator

Leave a Reply

Your email address will not be published. Required fields are marked *