Iterators and generators for real parameter higher order functions

Posted by tibberous on Tue, 26 Oct 2021 12:24:34 +0200

1, Real parameter higher order function

1. Essence of function

A function is a variable

Python defines a variable whose type is function, and the function name is the variable name

2.map function

Map (function, sequence) -- the elements in the sequence are converted into elements in a new sequence through specified rules

Function requirements:
There is and only one parameter - pointing to each element in the following sequence

There is a return value -- the element in the new sequence (use parameters to represent the element in the original sequence and describe the relationship between the element in the new sequence and the element in the original sequence)

# Exercise 5: there are two lists: student name and age. Create a list to save multiple student information according to the
# [{name ':' Xiao Ming ',' age ': 18}, {name': 'Zhang San', 'age': 21}, {name ':' Li Si ',' age ': 22}, {name': 'Lao Wang', 'age': 19}]
names = ['Xiao Ming', 'Zhang San', 'Li Si', 'Lao Wang']
ages = [18, 21, 22, 19]
new_list = list(map(lambda name, age: {'name': name, 'age': age}, names, ages))
print(new_list)
# [{name ':' Xiao Ming ',' age ': 18}, {name': 'Zhang San', 'age': 21}, {name ':' Li Si ',' age ': 22}, {name': 'Lao Wang', 'age': 19}]
3.reduce function

Reduce (function, sequence, initial value)

Function requirements: there are only two parameters -- the first parameter points to the initial value in the sequence, and the second parameter points to the elements in the sequence

# Exercise 3: merge the elements in names - > 'Xiao Zhang, Li Lao'
names = ['Xiao Ming', 'Zhang San', 'Li Si', 'Lao Wang']
result = reduce(lambda init, name: init + name[0], names, '')
print(result) # Xiao Zhang, Li Lao

# Exercise 6: know a list of students
students = [
    {'name': 'Xiao Ming', 'age': 18, 'math': 90, 'chinese': 85, 'English': 60},
    {'name': 'stu1', 'age': 22, 'math': 83, 'chinese': 80, 'English': 30},
    {'name': 'stu2', 'age': 30, 'math': 67, 'chinese': 93, 'English': 87},
    {'name': 'stu3', 'age': 19, 'math': 55, 'chinese': 76, 'English': 69},
    {'name': 'stu4', 'age': 17, 'math': 79, 'chinese': 80, 'English': 90}
]
# 1) Seek the average score of class Chinese score
sum1 = reduce(lambda init, student: init + student['chinese'], students, 0)
print(f'average{sum1 / len(students)}') # Average score 82.8
# 2) Sort the list from large to small according to the average score of students
new_students = sorted(students, key=lambda x: x['math'] + x['chinese'] + x['English'], reverse=True)
print(new_students)
"""
[{'name': 'stu4', 'age': 17, 'math': 79, 'chinese': 80, 'English': 90}, {'name': 'stu2', 'age': 30, 'math': 67, 'chinese': 93, 'English': 87}, {'name': 'Xiao Ming', 'age': 18, 'math': 90, 'chinese': 85, 'English': 60}, {'name': 'stu3', 'age': 19, 'math': 55, 'chinese': 76, 'English': 69}, {'name': 'stu1', 'age': 22, 'math': 83, 'chinese': 80, 'English': 30}]
"""

# 3) Associate the data in address to each student in turn
def add_address(dict1, addr):
    dict1['address']= addr
    return dict1


address = ['Chongqing', 'Chengdu', 'Beijing', 'Kunming', 'Shenzhen']
result = list(map(add_address, students, address))
print(result)
"""
[{'name': 'Xiao Ming', 'age': 18, 'math': 90, 'chinese': 85, 'English': 60, 'address': 'Chongqing'}, {'name': 'stu1', 'age': 22, 'math': 83, 'chinese': 80, 'English': 30, 'address': 'Chengdu'}, {'name': 'stu2', 'age': 30, 'math': 67, 'chinese': 93, 'English': 87, 'address': 'Beijing'}, {'name': 'stu3', 'age': 19, 'math': 55, 'chinese': 76, 'English': 69, 'address': 'Kunming'}, {'name': 'stu4', 'age': 17, 'math': 79, 'chinese': 80, 'English': 90, 'address': 'Shenzhen'}]
"""

2, Iterator

1. What is an iterator

Iterators are container data types -- they can be traversed or converted into lists or tuples

The print iterator cannot view elements; Unable to count the number of elements in the iterator

If you want to get the element of the iterator, you must take the element out of the iterator, and once the element is taken out, the element does not exist in the iterator and cannot be added again.

2. How to create iterators

Method 1: use iter to convert other sequences into iterators

iter1=iter([10,20,30,40])
for x in iter1:
    print(x,end='and') # 10and20and30and40and
print()
print(iter1) # <list_iterator object at 0x000002233FB22460>
# print(len(iter1)) # print(len(iter1))
# print(iter1[0]) # TypeError: 'list_iterator' object is not subscriptable

Method 2: create a generator

3. Get the elements of the iterator

No matter how you get the elements in the iterator, the obtained elements will disappear from the iterator

1) Get a single element

Next (iterator) -- get the top element of the current iterator

2) Traversal

iter2=iter({'name':'Zhang San','age':18,'gender':'male'})
print(next(iter2)) # name
for x in iter2:
    print(f'x:{x}')
"""
x:age
x:gender
"""

3, Generator

1. What is a generator

A generator is a container (it does not store multiple data, but an algorithm that generates multiple data) -- it can be traversed or converted into lists, tuples, etc

The generator has all the characteristics of iterators: elements cannot be seen in printing, and the number cannot be counted. Once elements are obtained, the corresponding elements will disappear from the generator

2. How to create a generator

Call a function with the yield keyword to get a generator.

If an ordinary function is called, the function body will be executed and the return value of the function will be obtained when calling the function;

If the function body of the called function is yield, the function body will not be executed and the return value of the function will not be obtained when calling the function, and a generator object will be obtained

def func1():
    print('=======')
    yield 100
    print('+++++++')
    yield 200
    print('-------------')
    return 1


result = func1()
print(next(result))
"""
=======
100
"""
print(next(result))
"""
+++++++
200
"""
3. Control the number and value of data generated by the generator

How many data can be generated by the generator and what data can be generated are determined by the function body of the function called when the generator is created, how many times yield is encountered during execution, and the value after yield each time yield is encountered

def func1():
    yield 100
    yield 200
    yield 300


gen1 = func1()
print(list(gen1)) # 100
print(list(gen1)) # 200
print(list(gen1)) # 300

# Exercise 1: write a function to create a generator for Python students' student numbers
# 'python001','python002',.... 'python999'


def student_id():
    for x in range(1, 1000):
        yield f'python{x:0>3}'


student_gen = student_id()
print(next(student_gen)) # python001

# Exercise 2: write a function to create a generator for the student number of students in a specified subject
# python   ->  'python001','python002',.... 'python999'
# java     ->   'java001','java002',.... 'java999'


def students_id(str1):
    for x in range(1, 1000):
        yield f'{str1}{x:0>3}'


java_gen = students_id('java')
python_gen = students_id('python')
print(next(java_gen)) # java001
print(next(python_gen)) # python001

Topics: Python