Python-list comprehension & generator

List comprehension

format:

list1 = [The expression that generates the element for the element of the original list in the original list if the conditions that need to be met]

use:

The following code is an example, you can see that the square of all even elements in list0 is stored in the final list1.
The process of its operation is to take out the variable i of the elements from list0 one by one, and then determine whether i is divisible by 2. If it is divisible, execute the initial expression, i * i, and then put this element in the new list
It can be seen as, the list comprehension is to derive a new list from the old list

list0 = [2, 5, 6, 7, 4]
list1 = [i * i for i in list0 if i % 2 == 0]
print(list1)
'''
输出:
[4, 36, 16]
'''

There are many other uses of list comprehensions. Here are a few examples:
Use ternary operators

list0 = [2, 5, 6, 7, 4]
list1 = [i * i if i % 2 else -i for i in list0]
print(list1)
'''
输出:
[-2, 25, -6, 49, -4]
'''
# 这里Py的非零整数就是True,零就是False

Operate on string elements

list0 = ['abc', 'ccc', 'here', 'cute']
list1 = [i * 5 for i in list0 if len(i) > 3]
print(list1)
'''
输出:
['hereherehereherehere', 'cutecutecutecutecute']
'''

Filter list elements

list0 = ['abc', 'ccc', 3, 'here', 'cute', 5, True, False]
list1 = [i for i in list0 if isinstance(i, str)]
print(list1)
'''
输出:
['abc', 'ccc', 'here', 'cute']
'''

Operate on dictionary elements

list0 = [{
    
    'key': 10}, {
    
    'key': 34}, {
    
    'key': 66}]
list1 = [i for i in list0 if i['key'] <= 10]
print(list1)
'''
输出:
[{'key': 10}]
'''

Loop nesting

list1 = [(i, j) for i in range(5) if i % 2 for j in range(5) if j % 2 == 0]
print(list1)
'''
输出:
[(1, 0), (1, 2), (1, 4), (3, 0), (3, 2), (3, 4)]
'''

List comprehension is faster than traversing the list one by one and adding a new list.

Set comprehension

In fact, it is the same as the list comprehension, except that there is more to remove the duplication.

set1 = {
    
    i % 2 for i in range(10)}
print(set1)
''''
输出:
{0, 1}
''''
Dictionary comprehension

The same as the list comprehension, but it will be overwritten according to the key, and the generated value will replace the first generated value

dict0 = {
    
    'aaa': 233, 'bbb': 332, 'ddd': 555}
dict1 = {
    
    key: value + 5 for key, value in dict0.items()}
print(dict1)
'''
输出:
{'aaa': 238, 'bbb': 337, 'ddd': 560}
'''

Reversing the key and value
can find that if there is a duplicate key after the reversal, the value will be replaced

dict0 = {
    
    'aaa': 233, 'bbb': 233, 'ddd': 555}
dict1 = {
    
    value: key for key, value in dict0.items()}
print(dict1)
'''
输出:
{233: 'bbb', 555: 'ddd'}
'''

Builder

Generator-expression

If the symbol of the above list comprehension is replaced with parentheses, then the newly generated generator is a generator:
as can be seen from the following code, list is no longer a list, but a generator object, of course it can still Force it to be converted into a list

list1 = (i * i for i in range(6))
print(list1)
'''
输出:
<generator object <genexpr> at 0x0000013E4C03F5C8>
'''

At this point, if you want to get the element, you need to use the next method

generator = (i * i for i in range(6))
print(generator.__next__()) # 使用自带的__next__()方法来返回下一个元素
print(generator.__next__())
'''
输出:
0
1
'''
generator = (i * i for i in range(6))
print(next(generator))# 使用系统自带的next函数
print(next(generator))
print(next(generator))
'''
输出:
0
1
4
'''

It should be noted that the two types of next only return the next element each time, and cannot skip an element or return from any point, and the generator is of an iterable type.
Traversal generator

generator = (i * i for i in range(6))
for i in generator:
    print(i)
'''
输出:
0
1
4
9
16
25
'''

Use map mapping

generator = (i * i for i in range(6))
print(list(map(lambda x: x * x, generator)))
'''
输出:
[0, 1, 16, 81, 256, 625]
'''
Generator-function

Using expressions can only create simple expressions. If it is a little more complicated, you need to use functions.

yield keyword

Through the following code, you can see that after the yield keyword is added to the function, the function becomes a generator

def generator(n: int):
    cnt = 1
    while cnt < n:
        cnt += n
        yield cnt


print(generator(5))
'''
输出:
<generator object generator at 0x0000024845B154C8>
'''

You can know the general process of the program from the following code (it is recommended to debug to see the process again)

  1. ge obtained the address of the generator object, but did not execute the code inside the generator
  2. Execute the first next, start executing the internal code, first execute the outermost initialization cnt, then enter the loop, until the yield keyword is executed, cnt is returned as the value obtained at the time, and then the internal execution of the generator stops
  3. Execute the second next, you can find that after printing'yield', it means that the second execution is executed after the last time the yield ended.
def generator(n: int):
    cnt = 1
    print("进入生成器")
    while cnt < n:
        cnt += 1
        print("yield之前")
        yield cnt
        print("yield后")


ge = generator(5)
print("得到生成器----开始获取元素", end='\n\n\n')
print(ge.__next__())
print("第一个元素获取完毕", end='\n\n\n')
print(ge.__next__())
print("第二个元素获取完毕", end='\n\n\n')
'''
输出:
得到生成器----开始获取元素


进入生成器
yield之前
2
第一个元素获取完毕


yield后
yield之前
3
第二个元素获取完毕

'''

It is concluded that the variable after the yield will be returned as a value, and after encountering the yield, the code inside the generator will stop executing until the next next is called. Give another example:

def generator(n: int):
    cnt = 1
    print("进入生成器")
    cnt += 1
    yield cnt
    yield 23333


ge = generator(5)
print(ge.__next__())
print(ge.__next__())
'''
输出:
进入生成器
2
23333
'''

You can think of yield as a special return, but the current iterator will not end after execution. In fact, yield can be used without the returned value so that yield can be used as a suspended tool.

Function generator and return

Executing the following code will cause an exception, because the current generator can only generate two elements, but it has executed three next

def generator(n: int):
    cnt = 1
    cnt += 1
    yield cnt
    yield 23333


ge = generator(5)
print(ge.__next__())
print(ge.__next__())
print(ge.__next__())
'''
輸出:
2
23333
Traceback (most recent call last):
  File "D:\Pycharm\Project\Pytest\test.py", line 11, in <module>
    print(ge.__next__())
StopIteration
'''

If you add a return here, you can find that the value of return is output as an abnormal message

def generator(n: int):
    cnt = 1
    cnt += 1
    yield cnt
    yield 23333
    return "生成器结束"


ge = generator(5)
print(ge.__next__())
print(ge.__next__())
print(ge.__next__())
'''
输出:
Traceback (most recent call last):
2
  File "D:\Pycharm\Project\Pytest\test.py", line 12, in <module>
23333
    print(ge.__next__())
StopIteration: 生成器结束
'''
send method

Use the send method on the generator, you can pass in a value to the generator, and also get the return element of the generator, so that the generator can communicate with the outside world

The information sent when using send is equivalent to the value of yield, so use a variable to receive the value of yield.

Note that you can only pass None when you first use send, otherwise an error will be reported.
The reason is very simple. After analyzing the execution process of the generator above, it can be known that when the generator is executed for the first time, the execution ends when the yield is executed, that is, there is no opportunity for the yield to receive the value, so the value will be reported as an error.
It is recommended to debug the understanding process

def generator(n: int):
    cnt = 1
    while cnt < n:
        cnt += 1
        message = yield cnt
        print(message)


ge = generator(5)
print(ge.send(1005))
'''
输出:
Traceback (most recent call last):
  File "D:\Pycharm\Project\Pytest\test.py", line 10, in <module>
    print(ge.send(1005))
TypeError: can't send non-None value to a just-started generator
'''

use correctly:

def generator(n: int):
    cnt = 1
    while cnt < n:
        cnt += 1
        message = yield cnt
        print(message)


ge = generator(5)
print(ge.send(None))
print(ge.send(1005))
print(ge.send(1005))
'''
输出:
2
1005
3
1005
4
'''

You can also:

def generator(n: int):
    cnt = 1
    while cnt < n:
        cnt += 1
        message = yield cnt
        print(message)


ge = generator(5)
print(ge.__next__())
print(ge.send(1005))
print(ge.send(1005))
'''
输出:
2
1005
3
1005
4
'''

In short, the yield must be executed once before using send to send non-None messages.

Guess you like

Origin blog.csdn.net/qq_36102055/article/details/107425854