实参高阶函数迭代器和生成器
1.函数就是变量
pythonz中定义函数其实就是定义一个类型是function的变量,函数名就是变量名
变量 = lambda 参数列表:返回值
相当于:
def 变量(参数列表)
return 返回值
a = [10, 20, 30]
def b():
print('你好世界')
c1 = a
print(a[-1])
print(c1[-1])
c2 = b
b()
c2()
c3 = b()
list1 = [100, a, b, b()]
print(list1)
print(list1[1][-1])
list1[2]()
2.实参高阶函数
2.1map :
将一个或者多个序列中的元素通过指定规则创建一个新的序列
map(函数,序列)— 将序列中的元素通过函数指定的规则转换成一个新的序列中的元素
函数要求:有且只有一个参数 — 指向后面的这个序列中的每个元素
有一个返回值 — 新序列中元素(有参数来代表原序列中的元素,描述出新序列中元素和原序列元素的关系)
map(函数,序列1,序列2)— 将两个序列中的元素通过函数指定的规则转换成一个新的序列中的元素
函数的要求:有且只有两个参数 — 分别指向后面两个序列中的元素
有一个返回值 — 新序列中元素(用参数来代表原序列中的元素,描述出新序列中元素和原序列元素的关系)
map(函数,序列1,序列2,序列3)
函数的要求:有且只有三个参数 — 分别指向后面三个序列中的元素
有一个返回值
# 练习1: 获取nums中所有元素的个位数 -> [4, 2, 7, 0, 1]
nums = [84, 72, 67, 90, 31]
# 方法一:列表推导式
new_nums = [x % 10 for x in nums]
print(new_nums)
# 方法二:map
new_nums = list(map(lambda x: x % 10, nums))
print(new_nums)
# 练习2:创建一个序列,序列中的元素是nums1和nums2对应位置上元素的和 - [32, 97, 97, 25]
nums1 = [23, 8, 90, 2]
nums2 = [9, 89, 7, 23]
new_nums = list(map(lambda x1, x2: x1 + x2, nums1, nums2))
print(new_nums) # [32, 97, 97, 25]
# 练习3:通过将nums中的元素乘以10转换成一个新的序列 -> [230, 80, 900, 20]
# 要求:使用推导式和map
nums = [23, 8, 90, 2]
# 方法一:
new_nums = [x * 10 for x in nums]
# 方法二:
new_nums = list(map(lambda x: x * 10, nums))
print(new_nums)
# 练习4:已知两个数字列表,将第一个列表中元素的个位数作为十位数,第二个列表中元素的个位数作为个位数创建一个新的序列
# [39, 89, 47, 21]
nums1 = [23, 8, 914, 2]
nums2 = [9, 89, 37, 231]
new_nums = list(map(lambda x1, x2: x1 % 10 * 10 + x2 % 10, nums1, nums2))
print(new_nums)
new_nums = list(map(lambda x1, x2: int(f'{x1 % 10}{x2 % 10}'), nums1, nums2))
print(new_nums)
# 练习5:已经两个列表分别是学生姓名和年龄,根据创建一个保存多个学生信息的列表
# [{'name': '小明', 'age': 18}, {'name': '张三', 'age': 21}, {'name': '李四', 'age': 22}, {'name': '老王', 'age': 19}]
names = ['小明', '张三', '李四', '老王']
ages = [18, 21, 22, 19]
students = list(map(lambda name, age: {'name': name, 'age': age}, names, ages))
print(students)
def temp(name, age):
"""临时函数"""
return {'name': name, 'age': age}
students = list(map(temp, names, ages))
print(students)
2.2reduce :
将序列中的元素按照指定的规则合并成一个数据
reduce(函数,序列,初始值)
函数的要求:有且只有两个参数 — 第一个参数指向初始值,第二个参数指向序列中的元素
返回值 — 确定合并方式(看元素和初始值进行什么样的操作来进行合并的)
from functools import reduce
# 练习: 求nums中所有元素的和 -> 118 => 0 + 10 + 20 + 32 + 56
nums = [10, 20, 32, 56]
result = reduce(lambda init, item: init + item, nums, 0)
print(result)
# 练习2:求nums中所有元素的乘积 -> 480 => 1 * 2 * 3 * 8 * 10
nums = [2, 3, 8, 10]
result = reduce(lambda init, item: init * item, nums, 1)
print(result)
# 练习3:和并nums中的数据 -> '23810' -> int('23810') =>'' + str(2) + str(3) + str(8) + str(10)
nums = [2, 3, 8, 10]
result = reduce(lambda init, item: init + str(item), nums, '')
print(result, int(result))
# 练习3:将names中的元素合并 -> '小张李老'
# '' + '小' + '张' + '李' + '老'
# '' + '小明'[0] + '张三'[0] + '李四'[0] + '老王'[0]
names = ['小明', '张三', '李四', '老王']
result = reduce(lambda init, item: init + item[0], names, '')
print(result)
# 练习4:将nums中所有的元素按照数值大小求和 -> 40.0
# 0 + float(10) + float('12') + float(12.5) + float('5.5')
nums = [10, '12', 12.5, '5.5']
result = reduce(lambda init, item: init + float(item), nums, 0)
print(result)
# 练习5:将nums中所有的数字数据求和 -> 12 + 100 + 10.5 -> 122.5
# 两种方法:使用推导式、不用推导式
nums = [12, 'abc', '12.5', 100, 10.5]
# 方法一
# nums = [12, 100, 10.5] -> 0 + 12 + 100 + 10.5
result = reduce(lambda init, item: init + item, [x for x in nums if type(x) in (int, float)], 0)
print(result)
# 方法二
# [12, 'abc', '12.5', 100, 10.5] -> 0 + 12 + 0 + 0 + 100 + 10.5
result = reduce(lambda init, item: init + (item if type(item) in (int, float) else 0), nums, 0)
print(result)
# 练习6:已知一个学生列表
students = [
{'name': '小明', '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) 求班级语文成绩的平均成绩 - reduce
total_chinese = reduce(lambda init, item: init + item['chinese'], students, 0)
print('语文平均分:', total_chinese / len(students))
# 2)按照学生的平均分对列表从大到小排序 - sored、sort
# students.sort(key=lambda stu: stu['math'] + stu['chinese'] + stu['English'], reverse=True)
# print(students)
new_students = sorted(students, key=lambda stu: stu['math'] + stu['chinese'] + stu['English'], reverse=True)
print(new_students)
# 3)将address里面的数据依次关联到每个学生中 - map
address = ['重庆', '成都', '北京', '昆明', '深圳']
def temp(stu, addr):
stu['address'] = addr
return stu
new_students = list(map(temp, students, address))
print(new_students)
3.迭代器
3.1什么是迭代器
迭代器是容器型数据类型 — 可以遍历,也可以转换成列表或者元组等
打印迭代器无法查看元素:无法统计迭代器中元素的个数:
如果要获取迭代器的元素,必须将元素从迭代器中取出来,而且元素一旦取出,这个元素在迭代器中就不存在,也无法重新添加。
3.2怎么创建迭代器
方法一:用iter将其他的序列转换成迭代器(任何序列都可以转换成迭代器)
方法二:创建一个生成器
iter1 = iter('hello')
iter2 = iter([10, 20, 30])
iter3 = iter({'name': '张三', 'age': 18})
iter4 = iter({100, 200, 300})
迭代器打印无法查看元素
print(iter1) # <str_iterator object at 0x1074358e0>
print(iter2) # <list_iterator object at 0x1070138b0>
迭代器不能统计元素个数
# print(len(iter1)) # TypeError: object of type 'str_iterator' has no len()
3.3获取迭代器的元素
不管以什么样的方式得到了迭代器中的元素,那么被获取到的元素一定会从迭代器中消失
1)获取单个元素
next(迭代器) — 获取当前迭代器最上面的那个元素
2)遍历
for 变量 in 迭代器:
循环体
iter1 = iter('hello')
print(next(iter1)) # h
print(next(iter1)) # e
print(next(iter1)) # l
print(next(iter1)) # l
print(next(iter1)) # o
# print(next(iter1)) # 报错:StopIteration
iter2 = iter([10, 20, 30])
for x in iter2:
print(f'x:{x}')
# print(next(iter2)) # 报错:StopIteration
iter3 = iter({'name': '张三', 'age': 18, 'gender': '男'})
print(next(iter3)) # 'name'
for x in iter3:
print(f'x:{x}')
iter1 = iter('hello')
print(list(iter1)) # ['h', 'e', 'l', 'l', 'o']
# print(next(iter1)) # 报错:StopIteration
4.生成器
4.1)什么是生成器
生成器是一种容器(保存不是多个数据,而是产生多个数据的算法)— 可以遍历,也可以转换成列表、元组等
生成器具备迭代器所有的特点:打印无法看到元素、无法统计个数、元素一旦获取对应的元素就会从生成器中消失
4.2)怎么创建生成器
调用一个带有yield关键字的函数就可以得到一个生成器。
如果调用的是普通函数,调用函数的时候会执行函数体,并且获取函数返回值:
如果调用的函数体中有yield,调用函数的时候不会执行函数体,也不会获取函数返回值,得到的是一个生成器对象。
def func1():
print('=======')
print('+++++++')
print('--------')
yield
# if False:
# yield
return 100
result = func1()
print(result) # <generator object func1 at 0x1031f6b30>
4.3)控制生成器产生数据的个数和值
生成器能产生多少个数据,能产生哪些数据由创建生成器的时候调用的那个函数的函数体,在执行的时候会遇到几次yield以及每次遇到yield的时候,yield后面的值来决定。
def func1():
yield 100
yield 200
if 10 > 20:
yield 400
return 300
yield 300
gen1 = func1()
print(list(gen1)) # [100, 200]
# print(next(gen1)) # 报错: StopIteration
# 练习: 写一个生成器可以创建3个元素,分别是100、200和300
def create_num():
# yield 100
# yield 200
# yield 300
for x in range(100, 301, 100):
yield x
gen2 = create_num()
print(next(gen2))
print(next(gen2))
print(next(gen2))
# print(next(gen2)) # 报错:StopIteration
# print(next(create_num())) # 100
# print(next(create_num())) # 100
# print(next(create_num())) # 100
4.4)生成器产生数据的原理
def func1():
yield 100
yield 200
if 10 > 20:
yield 400
return 300
yield 300
gen1 = func1()
print(list(gen1)) # [100, 200]
# print(next(gen1)) # 报错: StopIteration
# 练习: 写一个生成器可以创建3个元素,分别是100、200和300
def create_num():
# yield 100
# yield 200
# yield 300
for x in range(100, 301, 100):
yield x
gen2 = create_num()
print(next(gen2))
print(next(gen2))
print(next(gen2))
# print(next(gen2)) # 报错:StopIteration
# print(next(create_num())) # 100
# print(next(create_num())) # 100
# print(next(create_num())) # 100
5.模块的使用
5.1)什么是模块
一个py文件就是一个模块,模块名就是py文件的文件名
5.2)怎么在一个模块中使用另外一个模块中的内容
前提:只有模块名字是标识符并且不是关键字的模块才能被其他模块使用
原则:先导入才能用
5.3)模块的分类
系统模块 — Python环境中自带的py文件
自定义模块 — 程序员自己创建的py文件
5.4)怎么导入模块
1)import 模块名 — 导入指定模块,导入后可以通过‘模块名.’的方式使用这个模块中所有的全局变量
2)from 模块名 import 变量1,变量2,… — 导入指定模块,导入后可以直接使用对应的变量
3)from 模块名 import * — 导入指定模块,导入后可以直接使用模块中所有的全局变量
4)重命名
import 模块名 as 新模块名 — 对模块重命名
from 模块名 import 变量1 as 新变量1,变量2,… — 对变量重命名
# 导入方式1
# import test
# print(test.a)
# print(test.name)
# test.func1()
# import functools
# functools.reduce()
# 导入方式2
# from test import a, func1
# print(a)
# func1()
# # print(name) # NameError: name 'name' is not defined
# from functools import reduce
# reduce()
# 导入方式3
# from test import *
# print(a)
# print(name)
# func1()
# 模块重命名
# import test as ts
# print(ts.a)
# print(ts.name)
# ts.func1()
# import test as ts
# test = '好好学习!'
# print(test[-1])
# ts.func1()
# from test import a, name as t_name
# name = '小明'
# print(name)
# print(t_name)
#
# print(a)
# import math
# print(math.factorial(10))
# from math import factorial
# print(factorial(10))
from math import factorial as fac
print(fac(10))
课后作业
# 1.已经列表points中保存的是每个点的坐标(坐标是用元组表示的,第一个值是x坐标,第二个值是y坐标)
points = [(10, 20), (0, 100), (20, 30), (-10, 20), (30, -100)]
# 以下问题使用实参高阶函数来解决
# 1)获取列表中y坐标最大的点
result = max(points, key=lambda item: item[-1])
print(result)
print('--------------------分割线------------------------')
# 2)获取列表中x坐标最小的点
result1 = min(points, key=lambda item: item[0])
print(result1)
print('--------------------分割线------------------------')
# 3)获取列表中距离原点最远的点
result2 = max(points, key=lambda item: (item[0]) ** 2 + (item[-1] ** 2))
print(result2)
print('--------------------分割线------------------------')
# 4)将点按照点到x轴的距离大小从大到小排序
points.sort(key=lambda item: item[1] if item[1] >= 0 else -item[1], reverse=True)
print(points)
print('--------------------分割线------------------------')
result3 = sorted(points, key=lambda item: item[1] if item[1] >= 0 else -item[1], reverse=True)
print(result3)
print('--------------------分割线------------------------')
# 2.求列表 nums 中绝对值最大的元素
nums = [15, 8, 36, -12, -58, 168, -72]
result4 = max(nums, key=lambda item: item if item >= 0 else -item)
print(result4)
print('--------------------分割线------------------------')
# 3.已经两个列表A和B,用map函数创建一个字典,A中的元素是key,B中的元素是value
A = ['name', 'age', 'sex']
B = ['张三', 18, '女']
新字典: {'name': '张三', 'age': 18, 'sex': '女'}
result5 = dict(map(lambda A1, B1: (A1, B1), A, B))
print(result5)
print('--------------------分割线------------------------')
# 4.已知三个列表分别表示5个学生的姓名、学科和班号,使用map将这个三个列表拼成一个表示每个学生班级信息的的字典
names = ['小明', '小花', '小红', '老王']
nums = ['1906', '1807', '2001', '2004']
subjects = ['python', 'h5', 'java', 'python']
# 结果:{'小明': 'python1906', '小花': 'h51807', '小红': 'java2001', '老王': 'python2004'}
result6 = dict(map(lambda x, y, z:(x, (z + y)), names, nums, subjects))
print(result6)
print('--------------------分割线------------------------')
# 5.已经一个列表message, 使用reduce计算列表中所有数字的和(用采用列表推导式和不采用列表推导式两种方法做)
message = ['你好', 20, '30', 5, 6.89, 'hello']
# 结果:31.89
from functools import reduce
# 方法一:
result7 = reduce(lambda init, item: init + (item if type(item) in (int, float) else 0), message, 0)
print(result7)
print('--------------------分割线------------------------')
# 方法二:
result8 = reduce(lambda init, item: init + item, [x for x in message if type(x) in (int, float)], 0)
print(result8)
print('--------------------分割线------------------------')
# 6.已知一个字典列表中保存的是每个学生各科的成绩,
# 1)计算并添加每个学生的平均分
studens = [
{'name': 'stu1', 'math': 97, 'English': 67, 'Chinese': 80},
{'name': 'stu2', 'math': 56, 'English': 84, 'Chinese': 74},
{'name': 'stu3', 'math': 92, 'English': 83, 'Chinese': 78},
{'name': 'stu4', 'math': 62, 'English': 90, 'Chinese': 88}
]
list1 = list(map(lambda student: (student['math'] + student['English'] + student['Chinese']) / 3, studens))
print(list1)
def temp(stu, score):
stu['平均分'] = score
return stu
result9 = list(map(temp, studens, list1))
print(result9)
print('--------------------分割线-----------------------')
# 2)按照平均分从高到低排序
# 计算平均分
studens = [
{'name': 'stu1', 'math': 97, 'English': 67, 'Chinese': 80, 'avg':81},
{'name': 'stu2', 'math': 56, 'English': 84, 'Chinese': 74, 'avg':71},
{'name': 'stu3', 'math': 92, 'English': 83, 'Chinese': 78, 'avg':87},
{'name': 'stu4', 'math': 62, 'English': 90, 'Chinese': 88, 'avg':80}
]
# 按照平均分从高到低排序
result10 = sorted(studens, key=lambda item: item['avg'], reverse=True)
print(result10)