Day12 - 实参高阶函数迭代器和生成器

一、函数的本质

1. 函数就是变量
# Python中定义函数其实就是定义一个类型是function的变量,函数名就是变量名
"""
变量 = lambda 参数列表: 返回值

相当于
def 变量(参数列表):
    return 返回值
"""
a = [10, 20, 30]


def b():
    print('你好世界')


c1 = a
print(a[-1])        # 30
print(c1[-1])       # 30

c2 = b
b()                 # 你好世界
c2()                # 你好世界
# c3 = b()            # Function 'b' doesn't return anything
# print(c3)           # None

list1 = [100, a, b, b()]
print(list1)
# [100, [10, 20, 30], <function b at 0x0000027E6E3E4040>, None]

print(list1[1][-1])     # 30
list1[2]()              # 你好世界 调用函数

二、实参高阶函数

1. map – 将一个或者多个序列中的元素通过指定规则创建一个新的序列
"""
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)

# 练习3:通过将nums中的元素乘以10转换成一个新的序列 -> [230, 80, 900, 20]
# 要求:使用推导式和map
nums = [23, 8, 90, 2]
# 推导式
new_nums = [x*10 for x in nums]
print(new_nums)
# map
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, 7, 231]
new_nums = list(map(lambda x1, x2: (x1 % 10)*10 + x2 % 10, nums1, nums2))
# 字符串
# 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 x1, x2: {'name': x1, 'age': x2}, names, ages))
print(students)


def temp(name, age):
    return {'name': name, 'age': age}


students = list(map(temp, names, ages))
print(students)
2. reduce – 将序列中的元素按照指定的规则合并成一个数据
from functools import reduce            # 模块导入
"""
reduce(函数, 序列, 初始值)
函数要求:有且只有两个参数  --  第一个参数指向初始值,第二个参数指向序列中的每个元素
返回值  --  确定合并方式(看元素和初始值进行什么样的操作来进行合并的)
"""
# 练习1:求nums中所有元素的和 -> 118
# 118
# init初值
nums = [10, 20, 32, 56]
result = reduce(lambda init, item: init+item, nums, 0)
print(result)

# 练习2:求nums中所有元素的乘积 -> 480
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) + ..
nums = [2, 3, 8, 10]
result = reduce(lambda init, item: init+str(item), nums, '')
print(result)

# 练习4:将names中的元素合并  -> '小张李老'
# '' + '小' + '张' + '李' + '老'
# '' + '小明'[0] + '张三'[0] + '李四'[0] + '老王'[0]
names = ['小明', '张三', '李四', '老王']
result = reduce(lambda init, item: init+item[0], names, '')
print(result)

# 练习5:将nums中所有的元素按照数值大小求和  -> 40
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]
result = sum(x for x in nums if type(x) in (int, float))
print(result)

nums = [12, 'abc', '12.5', 100, 10.5]
# 三目运算符
result = reduce(lambda init, item: init + item if type(item) in (int, float) else init, nums, 0)
# 对nums用推导式得到[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)

# 练习7:已知一个学生列表
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) 求班级语文成绩的平均成绩
chinese_total = reduce(lambda init, item: init+item['chinese'], students, 0)
result = chinese_total/len(students)
print(result)

# 2)按照学生的平均分对列表从大到小排序
# sorted()创建一个新的列表
rank_of_average = sorted(students, key=lambda item: (item['math']+item['chinese']+item['English'])/3, reverse=True)
# students.sort()
# students.sort(key=lambda item: (item['math']+item['chinese']+item['English'])/3, reverse=True)
print(rank_of_average)

# 3)将address里面的数据依次关联到每个学生中
address = ['重庆', '成都', '北京', '昆明', '深圳']


def temp(stu, add):
    stu['address'] = add
    return stu


new_students = list(map(temp, students, address))
print(new_students)

三、迭代器

1. 什么是迭代器(iter)
"""
迭代器是容器型数据类型  --  可以遍历,也可以转换成列表或者元组等
打印迭代器无法查看元素;无法统计迭代器中元素的个数
如果要获取迭代器的元素,必须将元素从迭代器中取出来,而且元素一旦取出,这个元素在迭代器中就不存在了,也无法重新添加
"""
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 0x0000027D2FBE6580>
print(iter2)            # <list_iterator object at 0x0000027D2FBE6B50>

# 迭代器不能统计元素个数
# print(len(iter1))
# TypeError: object of type 'str_iterator' has no len()
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}')         # x:age \n x:gender

iter1 = iter('hello')
print(list(iter1))    # ['h', 'e', 'l', 'l', 'o']
# print(next(iter1))    # 报错:StopIteration

四、生成器

1. 什么是生成器
"""
生成器是一种容器(保存的不是多个数据,而是产生多个数据的算法)  --  可以遍历,也可以转换成列表、元组等
生成器具备迭代器所有特点:打印无法看到元素、无法统计个数、元素一旦获取对应的元素就会从生成器中消失
"""
2. 怎么创建生成器
"""
调用一个带有yield关键字的函数就可以得到一个生成器

如果调用的是普通函数,调用函数的时候会执行函数体,并且获取函数返回值
如果调用的函数的函数体中有yield,调用函数的时候不会执行函数体,也不会获取函数返回值,得到的是一个生成器对象
"""


def func1():
    print('=======')
    print('+++++++')
    print('--------')
    yield
    # if False:
    #     yield
    return 100


result = func1()
print(result)  # <generator object func1 at 0x1031f6b30>
3. 控制生成器产生数据的个数和值
"""
生成器能产生多少个数据,能产生哪些数据由创建生成器的时候调用的那个函数的函数体,
在执行的时候会遇到几次yield以及每次遇到yield的时候,yield后面的值来决定。
"""


def func1():
    yield 100
    yield 200
    # if 10 > 20:
    #   yield 400       # This code is unreachable
    return 300
    # yield 300         # This code is unreachable


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))       # 100
print(next(gen2))       # 200
print(next(gen2))       # 300
# print(next(gen2))     # 报错:StopIteration

# print(next(create_num()))       # 100
# print(next(create_num()))       # 100
# print(next(create_num()))       # 100
# 一直在从新的生成器中打印出第一个元素
4. 生成器产生数据的原理
def func2():
    print('============')
    yield 100
    print('+++++++++++')
    yield 200
    print('----------')
    yield 300
    print('end')
    return 100
    # print('**********')       不可访问


gen3 = func2()
print(gen3)         # <generator object func2 at 0x0000016C5C68B820>
print('-----------第1次-------------')
print('next:', next(gen3))

print('-----------第2次-------------')
print('next:', next(gen3))

print('-----------第3次-------------')
print('next:', next(gen3))

print('-----------第4次-------------')
# print('next:', next(gen3))    StopIteration报错


# 练习1:写一个函数可以创建Python学生的学号的生成器
# 'python001'、'python002'、.... 'python999'
def python_student_id():
    for python_id in range(1, 1000):
        yield f'python{python_id:0>3}'


python_students = python_student_id()
print(next(python_students))
print(next(python_students))
for _ in range(5):
    print(next(python_students))


# 练习2:写一个函数可以创建指定学科的学生的学号的生成器
# python   ->  'python001'、'python002'、.... 'python999'
# java     ->   'java001'、'java002'、.... 'java999'
def student_id(subject: str):
    for id_student in range(1, 1000):
        yield f'{subject}{id_student:0>3}'


java_students = student_id('java')
python_students = student_id('python')
print(next(java_students))      # java001
print(next(python_students))    # python001

五、模块的使用

# 1. 什么是模块
# 一个py文件就是一个模块,模块名就是py文件的文件名


# 2. 怎么在一个模块中使用另外一个模块中的内容
# 前提:只有模块名字是标识符并且不是关键的模块才能被其他模块使用
# 原则:先导入才能用


# 3. 模块的分类
# 系统模块  --  Python环境中自带的py文件
# 自定义模块  --  程序员自己创建的py文件


# 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)           # 100
# print(test.name)        # test
# test.func1()            # test中的函数

# 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))          # 3628800
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值