Python入门第十一天-高阶函数

这篇博客详细介绍了Python中的高阶函数,包括函数作为变量的概念,实参高阶函数如max、min、sorted、map和reduce的使用,以及无参装饰器的原理和五种实现方法。通过实例解析了如何利用这些高阶函数增强代码的功能。

day11-高阶函数

一、高阶函数

1、函数就是变量

  • 定义函数就是在定义变量,函数名就是变量名
  • python中定义函数就是定义类型是function的变量,函数名就是变量名
  • 变量能做的函数都能做
  • 函数加括号是在获取返回值,假如使用时没有加括号,就是获得一个函数
x = 100
def func1():
    print('我是一个函数')
  • 一个变量可以给另外一个变量赋值
y = x
print(y + 100)

z = func1
z()        # 我是一个函数,令z调用函数
  • 修改变量的值
x = 'abc'
print(x + '123')     # abc123

func1 = 100        # 由函数变成了数字
print(func1 + 200)   # 300
  • 变量作为序列的元素
x = 100
list1 = [x, 200]
print(list1)      # [100, 200]

list2 = [func1, 200]
list2[0]()      # 调用函数:我是一个函数

list3 = [func1, 200, func1()]
print(list3)          # [<function func1 at 0x000001EF4BEBA048>, 200, None]
  • 变量作为函数的参数
def func2(m):
    print(f'x:{m}')

a = 100
func2(a)      # x:100
func2(func1)   # x:<function func1 at 0x000001B04CC4A048>
  • 变量作为函数的返回值
def func3():
    def s():
        print('我是小函数')
    return s

func3()()   # 我是小函数;func3() ->在调用函数,即s;相当于func3()() -> s()
  • 面试题
# 面试题
list3 = []
for i in range(5):
    list3.append(lambda x: x*i)   # lambda是函数体,定义函数时不会执行函数体
'''
i = 0 : [lambda x :x*i]
i = 1 : [lambda x :x*i, lambda x :x*i]
i = 2 : [lambda x :x*i, lambda x :x*i, lambda x :x*i]
i = 3 : [lambda x :x*i, lambda x :x*i, lambda x :x*i, lambda x :x*i]
i = 4 : [lambda x :x*i, lambda x :x*i, lambda x :x*i, lambda x :x*i, lambda x :x*i]
list3 = [lambda x :x*i, lambda x :x*i, lambda x :x*i, lambda x :x*i, lambda x :x*i] 此处i = 4
'''

print(list3[1](2))   # 8
print(list3[2](2))   # 8

二、实参高阶函数

1、实参高阶函数

  • 参数是函数的函数就是实参高阶函数
# func1就是实参高阶函数
def func1(x):
    print(x())

def func2(m=10):
    print('您好!')

func1(func2)

2、系统常见的实参高阶函数的使用

  • max、min、sorted、map、reduce
(1)max 和 min
  • max(序列) - 比较序列中元素的大小来获取值最大的元素
  • max(序列,key = 函数)- 函数决定求最大值时的比较对象是什么
  • 参数key的要求:
  • a.必须是函数
  • b.这个函数有且只有一个参数(这个参数指向的就是序列中的元素)
  • c.函数要有一个返回值(比较对象)
  • d.key后面一般跟匿名函数,匿名函数后面是比较啥就取啥
nums = [23, 78, 90, 78, 233, 91]
print(max(nums))


# 求列表中个位数最大的元素
nums = [19, 78, 76, 55, 30, 12]
# def f1(item):
#     return item % 10
# result = max(nums, key=f1)
result = max(nums, key=lambda item: item % 10)
print(result)

students = [
    {'name': '小明', 'age': 23, 'score': 90},
    {'name': '张三', 'age': 30, 'score': 78},
    {'name': '小红', 'age': 18, 'score': 82},
    {'name': 'Tom', 'age': 26, 'score': 99}
]

# 求所有学生中成绩最高的学生
def f2(item):
    return item['score']
print(max(students, key= f2))
print(max(students, key=lambda item: item['score']))

def f3(item):
    return item['age']
print(min(students, key=lambda item:item['age']))

# 获取列表中数字的各位数的和最大的元素(取出列表单个元素中的每一个数字,即23 -> 2, 3)
nums = [23, 78, 90, 73, 233, 91]
print(max(nums, key=lambda item: (item % 10) + (item // 100) + (item // 10 % 10)))
# 用推导式将数字转换成字符串再一个一个的拿出来,再转换成整型再相加
print(max(nums, key=lambda item: sum(int(x) for x in str(item))))
(2)sorted
  • sorted(序列) - 比较序列中元素的大小,然后对序列中的元素从小到大的排序
  • sorted(序列, key = 函数) - 函数决定排序的时候比较大小的比较对象
  • 函数的要求:
  • a.是一个函数
  • b.需要一个参数(指向序列中的元素)
  • c.需要一个返回值(比较对象)
nums = [19, 23, 45, 67, 78]
result = sorted(nums)
print(result)

# 练习一:让列表中的元素按照个位数的大小从小到大排序
nums = [19, 23, 45, 67, 78]
print(sorted(nums, key=lambda item: item % 10))

# 练习2:将students按照学生的年龄从大到小排序
students = [
    {'name': '小明', 'age': 23, 'score': 90},
    {'name': '张三', 'age': 30, 'score': 78},
    {'name': '小红', 'age': 18, 'score': 82},
    {'name': 'Tom', 'age': 26, 'score': 99}
]

print(sorted(students, key=lambda item: item['age'], reverse=True))
(3)map
  • 用法一:原序列 -> 新序列
  • map(函数,序列) - 将序列按照指定的方式进行转换,返回值是一个map对象(map对象是序列)
  • 函数:a.有一个参数(这个参数指向原序列元素);b.需要一个返回值(新序列中的元素)
  • 推导式能完成的功能map都能完成
  • map能完成的推导式不一定能完成
# 用法一:
nums = [19, 23, 45, 67, 78]
result = map(lambda item: item, nums)

result1 = map(lambda item: item % 10, nums)
print(list(result1))        # [9, 3, 5, 7, 8]
result2 = map(lambda item: item * 2, nums)
print(list(result2))        # [38, 46, 90, 134, 156]
  • 用法二:将多个序列按照指定的方式合并成一个新的序列
  • map(函数,序列1,序列2)- 让序列1和序列2根据函数的范式来合并创建一个新的序列,序列1和序列2的个数要对应
  • 函数:a.有两个参数,分别指向两个序列中的元素;b.需要一个返回值(新序列中的元素)
# 用法二
names = ['张三', '李四', '小明', '小花']
ages = [19, 29, 30, 17]
result3 = map(lambda item1, item2: {'name': item1, 'age': item2}, names, ages)
print(list(result3))
# [{'name': '张三', 'age': 19}, {'name': '李四', 'age': 29}, {'name': '小明', 'age': 30}, {'name': '小花', 'age': 17}]

# 练习:获取班级所有学生的总成绩
c = [90, 89, 88, 99, 27, 76, 56]
e = [98, 78, 66, 82, 90, 12, 78]
m = [23, 98, 100, 72, 69, 27, 96]
result4 = map(lambda item1, item2, item3: item1+item2+item3, c, e, m)
print(list(result4))     # [211, 265, 254, 253, 186, 115, 230]
(4)reduce - 产生一个新的结果
  • reduce是没法直接使用的,需要先导入
  • 导入reduce:from functools import reduce
  • 用法:
  • reduce(函数,序列,初始值)
  • 函数的要求:
  • a.需要两个参数:
  • 第一个参数 - 第一次指向初始值;从第二次开始会指向上一次的运算结果
  • 第二个参数 - 指向序列中的每一个元素
  • b. 需要一个返回值
# 累计求和
nums = [10, 89, 78, 20]
from functools import reduce
# result5 = reduce(lambda s, item: s + item, nums, 0)
def f1(s, item):
    print(f's:{s}, item:{item}')
    return s+item
result5 = reduce(f1, nums, 0)
print(result5)      # 197
# s:0, item:10
# s:10, item:89
# s:99, item:78
# s:177, item:20
# 197

# f1(0, 10) -> 10
# f1(10, 89) -> 10 + 89 -> 99
# f1(99, 78) -> 99 + 78 -> 177
# f1(177, 20) -> 177 + 20 -> 197

# 累计求乘积
nums = [8, 9, 5, 2]
result5 = reduce(lambda s, item: s*item, nums, 1)
print(result5)

# 将数字序列中的元素全部合并,即拼接在一起
# [10, 89, 78, 20] -> 10897820
nums = [10, 89, 78, 20]
result6 = reduce(lambda s, item: s + str(item), nums, '')
print(result6)    # 10897820
result7 = reduce(lambda s, item: str(item) + s, nums, '')
print(result7)     # 20788910

三、无参装饰器

1、什么是装饰器

  • 作用: 装饰器是用来给函数添加功能

  • 本质:就是一个函数(实参高阶函数+个返回值高阶函数+语法)

  • 用法(套路):

  • def 函数名1(参数1):

    ​ def 函数名2()

    ​ 新增功能的代码

    ​ 调用原函数的代码 - 参数1()

    ​ return 函数名2

  • 说明:

  • 函数名1 - 装饰器的名称,根据需要新增的功能来进行命名

  • 参数1 - 需要添加功能的函数(原函数),一般命名成f、fn(实参高阶函数)

  • 函数名2 - 添加完功能的新函数的函数名,new_f、new_fn

  • 新增功能的代码和调用原函数的代码顺序是不一定的,要看具体添加的功能

给函数添加统计函数执行时间的功能

(1)方法一:
  • 给需要添加功能的函数添加新增功能的代码
  • 存在的问题:如果给不同的函数添加相同的功能,需要添加多遍
def func1():
    start = time.time()
    print('函数1的功能')
    end = time.time()
    print(f'执行时间:{end-start}')
def func2(x, y):
    print(x + y)
func1()
(2)方法二
  • 将需要添加的功能封装到一个函数中
  • 存在的问题:原函数并没有新增功能
def func3():
    print('hello word')##
    
def count_time(f):
    # 获取开始时间
    start = time.time()
    # 调用原函数
    f()
    # 获取结束时间
    end = time.time()
    # 计算时间差
    print(f'执行时间:{end-start}')

count_time(func3)
(3)方法三
  • 利用装饰器

  • 存在的问题:当原函数需要赋值变量时就无法给她进行装饰

  • def 函数名1(参数1):

    ​ def 函数名2()

    ​ 新增功能的代码

    ​ 调用原函数的代码 - 参数1()

    ​ return 函数名2

def count_time(f):
    def new_f():
        start = time.time()
        f()
        end = time.time()
        print(f'执行时间:{end - start}')
    return new_f
print('===============================')

def func5():
    print('hello python')

func5()    # hello python

print('=================================')
@count_time
def func5():
    print('hello python')

func5()    # hello python
           # 执行时间:0.0
(4)方法四
  • 可以给任何函数添加功能

  • 存在问题:如果添加的是一个有返回值的函数,最后返回值会全部变成None,无法做到原函数的返回值是多少,新函数的返回值就是多少

  • def 函数名1(参数1):

    ​ def 函数名2(*args, **kwarg)

    ​ 新增功能的代码

    ​ 调用原函数的代码 - 参数1(*args, **kwarg)

    ​ return 函数名2

def count_time(f):
    def new_f(*args, **kwargs):
        start = time.time()
        f(*args, **kwargs)
        end = time.time()
        print(f'执行时间:{end - start}')
    return new_f
@count_time
def func7(num1, num2):
    print(num1 + num2)

func7(10, 20)
(5)方法五
  • def 函数名1(参数1):

    ​ def 函数名2(*args, **kwarg)

    ​ 新增功能的代码

    ​ 原函数的返回值 = 调用原函数的代码 - 参数1(*args, **kwarg)

    ​ return 原函数的返回值

    ​ return 函数名2

def count_time(f):
    def new_f(*args, **kwargs):
        start = time.time()
        result = f(*args, **kwargs)
        end = time.time()
        print(f'执行时间:{end - start}')
        return result
    return new_f
def func8(x):
    return x**2
result = func8(9)
print(result)
'''
# 执行时间:0.0009984970092773438
# 81
'''

# 练习:写一个装饰器,在函数开始执行时打开‘start'
def print_start(f):
    def new_f(*args, **kwargs):
        print('start')
        result = f(*args, **kwargs)
        return result
    return new_f

@print_start
def func11(a, b):
    print(a + b)
func11(10, 20)

'''
start
30
'''
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值