【Python高级编程】—— 函数式编程总结(生成器、迭代器、匿名函数、高阶函数、返回函数、闭包、装饰器、偏函数)

本文涉及的产品
简介: Python函数式编程的一般概念及特点, 迭代器、生成器表达式、内置函数、常用高阶函数、递归与归约、实用模块和装饰器的用法, 以及避开Python严格求值顺序的变通方法、Web服务设计方法和一些优化技巧。

Python函数式编程总结

在这里插入图片描述


@TOC


一、生成器generator

1.引出生成器

  通过 列表⽣成式,我们可以直接创建⼀个 列表。但是,受到内存限制,列表容量肯定是有限的。⽽且,创建⼀个包含非常多个元素的列表,不仅占⽤很⼤的存储空间,如果我们仅仅需要访问前⾯⼏个元素,那后⾯绝⼤多数元素占⽤的空间都⽩⽩浪费了。
# -*- coding: utf-8 -*-
# @File  : 引出生成器.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 21:00

# 列表生成式
lst = [i for i in range(10)]
print(lst)
print(type(lst))

# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# <class 'list'>
  所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?接下来,引出我们的 生成器

2.创建生成器

  • 通过列表生成式创建
# -*- coding: utf-8 -*-
# @File  : 创建生成器.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 20:59

g = (i for i in range(10))
print(g)
print(type(g))

# <generator object <genexpr> at 0x0000021B19A11D60>
# <class 'generator'>
  这样就不必创建完整的 list,从⽽节省⼤量的空间。在 Python中,这种⼀边循环⼀边计算的机制,称为⽣成器: generator

  创建列表生成器的区别仅在于最外层的 [ ]( )lst 是⼀个列表,⽽ g 是⼀个⽣成器。我们可以直接打印出 lst 的每⼀个元素,但我们怎么打印出 g 的每⼀个元素呢?如果要⼀个⼀个打印出来,可以通过 next() 函数获得⽣成器的下⼀个返回值:

  • 通过 next() 函数获得⽣成器的下⼀个返回值
# -*- coding: utf-8 -*-
# @File  : 创建生成器.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 20:59

lst = [i for i in range(10)]
g = (i for i in range(10))
print(g)
print(type(g))


print(next(g))  # 0
print(next(g))  # 1
print(next(g))  # 2
print(next(g))  # 3
print(next(g))  # 4
print(next(g))  # 5
print(next(g))  # 6
print(next(g))  # 7
print(next(g))  # 8
print(next(g))  # 9
print(next(g)) 

在这里插入图片描述

  ⽣成器保存的是算法,每次调⽤ next(g) ,就计算出 g 的下⼀个元素的值,直到计算到最后⼀个元素,没有更多的 元素时,抛出 StopIteration 的异常。

  当然,这种不断调⽤ next() 实在是太繁琐了,虽然是点一次出现一次,但正 确的⽅法是使⽤ for 循环,因为⽣成器也是可迭代对象。

  • 也可以通过for-in循环打印出来
# -*- coding: utf-8 -*-
# @File  : 创建生成器.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 20:59

g = (i for i in range(10))
print(g)
print(type(g))


# print(next(g))  # 0
# print(next(g))  # 1
# print(next(g))  # 2
# print(next(g))  # 3
# print(next(g))  # 4
# print(next(g))  # 5
# print(next(g))  # 6
# print(next(g))  # 7
# print(next(g))  # 8
# print(next(g))  # 9
# print(next(g))

for i in g:
    print(i)

在这里插入图片描述

  所以,我们创建了⼀个⽣成器后,基本上永远不会调⽤ next() ,⽽是通过 for 循环来迭代它,并且不需要关心 StopIteration 异常。

  generator非常强大。如果推算的算法比较复杂,用类似列表生成式的 for 循环无法实 现的时候,还可以用函数来实现。比如,著名的斐波拉契数列Fibonacci,除第一个和第二个数外,任意一个 数都可由前两个数相加得到:1, 1, 2, 3, 5, 8, 13, 21, 34, ...

  斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

代码如下

# -*- coding: utf-8 -*-
# @File  : 函数写斐波那契数列.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 21:14


# 定义一个斐波那契函数
def fib(times):
    # 初始化
    n = 0
    a, b = 0, 1
    while n < times:
        print(b)
        a, b = b, a+b
        n += 1


fib(6)

在这里插入图片描述

  仔细观察,可以看出, fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似 generator

  也就是说,上面的函数离generator仅一步之遥。要把 fib 函数变 成generator,只需要把 print(b) 改为 yield(b) 就可以了。

  • 通过yield关键字创建

yield一般用于创建生成器:工作后返回变量值给生成器。

# -*- coding: utf-8 -*-
# @File  : yield创建生成器.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 21:17


def fib(times):
    # 初始化
    n = 0
    a, b = 0, 1
    while n < times:
        yield b
        a, b = b, a+b
        n += 1


f = fib(6)
print(f)
# <generator object fib at 0x00000197C5E56350>
# f 是一个生成器对象

print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))

在这里插入图片描述

  在上⾯ fib的例⼦,我们在循环过程中不断调⽤ yield ,就会不断中断。当然要给循环设置⼀个条件来退出循环,不然就会产⽣⼀个⽆限数列出来。同样的,把函数改成 generator后,我们基本上从来不会⽤ next() 来获取下⼀个返 回值,⽽是直接使⽤ for 循环来迭代:
# -*- coding: utf-8 -*-
# @File  : yield创建生成器.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 21:17


def fib(times):
    # 初始化
    n = 0
    a, b = 0, 1
    while n < times:
        yield b
        a, b = b, a+b
        n += 1


f = fib(6)
print(f)
# <generator object fib at 0x00000197C5E56350>
# f 是一个生成器对象

for i in f:
    print(i)

在这里插入图片描述


3.遍历生成器

  • 通过 for- in循环打印
  • 通过next()函数,已经遍历到生成器的结尾抛异常
  • objict内置的__next__()方法,已经遍历到生成器的结尾抛异常
  • send() 方法,生成器的第一个值必须是send(None),后面没有限制
# -*- coding: utf-8 -*-
# @File  : 遍历生成器.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 21:24


# 创建一个生成器g
g = (i for i in range(10))

# 1.使用next(g),当已经遍历到生成器的结尾抛异常
print(next(g))  # 0
print(next(g))  # 1

# 2.object内置的__next__:当已经遍历到生成器的结尾抛异常
print(g.__next__())  # 2
print(g.__next__())  # 3

# 3.send 函数,生成器第一个值必须是send(None),后面的值没有限制
print(g.send(None))  # 4
print(g.send(''))  # 5
print(g.send(1))  # 6

# 4.使用for-in循环
for i in g:
    print(i)
# 7
# 8
# 9

在这里插入图片描述


4.生成器总结

   ⽣成器是这样⼀个函数,它记住上⼀次返回时在函数体中的位置。对⽣成器函数的第⼆次(或第 n 次)调⽤跳转⾄该函数中间,⽽上次调⽤的所有局部变量都保持不变。

  ⽣成器不仅记住了它数据状态;⽣成器还记住了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。

生成器的特点:

  • 节约内存
  • 迭代到下⼀次的调⽤时,所使⽤的参数都是第⼀次所保留下的,在整个所有函数调⽤的参数都是第⼀次所调⽤时保留的,⽽不是新创建的。

二、迭代器iterator

1.什么是迭代器

  迭代器是访问集合的一种方式,可以记住遍历位置的对象,迭代器从集合的第一个元素开始访问,直到所有的元素被访问完才结束,只能往往前,不能后退。

可以直接作用于for循环的数据类型有以下几种:

  • 一类是集合数据类型:如:listtupledictsetstr等;
a = (1,)  # 元组
b = [1, 2]  # 列表
c = {}  # 空字典
d = ()  # 元组
s = set()
s1 = {None}  # 集合

print(type(c))  # 空集合 <class 'dict'>
print(type(d))  # <class 'tuple'>
print(type(s))  # 空集合 <class 'set'>
  • 一类是generator,包括生成器和yield关键字的生成器函数generator function
  ⽣成器不但可以作⽤于 for 循环,还可以被 next() 函数不断调⽤并返回下⼀个值,直到最后抛出 StopIteration 错误表示⽆法继续返回下⼀个值了。

这些可以直接作用于for循环的对象统称为可迭代对象Iterable.

2.Iterable可迭代对象判断

可以使用 instance()判断一个对象是否是 Iterable对象。

instance()函数

def isinstance(x, A_tuple): # real signature unknown; restored from __doc__
    """
    Return whether an object is an instance of a class or of a subclass thereof.
    (返回一个对象是类的实例还是类的子类。)
    
    A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the target to
    check against. This is equivalent to ``isinstance(x, A) or isinstance(x, B)
    or ...`` etc.
    
    (一个元组,如' ' isinstance(x, (A, B,…))' ',可以被指定为目标
    核对。这相当于' ' isinstance(x, A)或isinstance(x, B)
    or ...`` etc.)
    """
    pass

代码实现:

# -*- coding: utf-8 -*-
# @File  : iterable对象判断.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 22:09


from collections.abc import Iterable

print(isinstance([1], Iterable))  # True
print(isinstance({0, 1}, Iterable))  # True
print(isinstance((1, ''), Iterable))  # True
print(isinstance({1: 10}, Iterable))  # True
print(isinstance((i for i in range(10)), Iterable))  # True
print(isinstance(10, Iterable))  # False

在这里插入图片描述

  可以使⽤ isinstance() 判断⼀个对象是 否是 Iterable 对象,这里就产生一个疑问了,生成器都是 Iterator 对象,那么 listdictstr 是不是 Iterator ?为什么?。

3.Iterator迭代器判断

# -*- coding: utf-8 -*-
# @File  : iterator迭代器判断.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 22:40


from collections.abc import Iterator

print(isinstance((i for i in range(10) if i % 2 == 0), Iterator))  # True
print(isinstance([], Iterator))  # False
print(isinstance({}, Iterator))  # False
print(isinstance('abc', Iterator))  # False

在这里插入图片描述

  可以得出 listdictstr 不是 Iterator ,因为 Python的 Iterator 对象表示的是一个数据流, Iterator对象可以 被 next() 函数调用并不断返回下一个数据,直到没有数据时抛出 StopIteration 错误。

  可以把这个数据流看做 是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过 next() 函数实现按需计算下一个数据,所以Iterator 的计算是惰性的,只有在需要返回下一个数据时它才会计算。

  Iterator 甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的 那我们还可以通过 isinstance() 来判断是否是 Iterator 对象

注意: IteratorIterable ,一个是迭代器,一个是可迭代对象

  但是可以使用 iter() 函数将 listdictstrIterable 变成 Iterator

iter()函数.py

# -*- coding: utf-8 -*-
# @File  : iter()函数.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 22:46

from collections.abc import Iterator

print(isinstance(iter([]), Iterator))  # True
print(isinstance(iter({}), Iterator))  # True
print(isinstance(iter('abc'), Iterator))  # True

在这里插入图片描述


4.迭代器与可迭代对象

  所有可以作用于 for循环的对象都是 Iterable可迭代对象类型;

  可以作用于next()函数的对象都是itreator迭代器类型,他们表示一个惰性计算序列;

  集合数据类型listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

# -*- coding: utf-8 -*-
# @File  : 迭代器和可迭代对象.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/20 23:00


# 迭代器  可以被next()函数调⽤并不断返回下⼀个值的对象称为迭代器:Iterator。

from collections.abc import Iterator, Iterable
# iterable 可迭代对象
# iterator 迭代器

a = (1,)  # 元组
b = [1, 2]  # 列表
c = {}  # 空字典
d = ()  # 元组
s = set()
s1 = {None}  # 集合

print(type(c))  # 空集合 <class 'dict'>
print(type(d))  # <class 'tuple'>
print(type(s))  # 空集合 <class 'set'>


# isinstance判断
# 可作用于for循环的对象都是iterable类型
def fun(args):
    if isinstance(args, Iterable):
        print(f'{args}对象是可迭代对象')
    else:
        print(f'{args}对象不是可迭代对象')


fun(a)  # 函数调用
fun(b)
fun(c)
fun(d)
fun(s)
print('---------------------------')


# 渴作用与next()函数的对象都是iterator类型,他们表示一个惰性计算的序列
def fun1(args):
    if isinstance(args, Iterator):
        print(f'{args}对象是可迭代器')
    else:
        print(f'{args}对象不是可迭代器')


g = (i for i in range(10))
fun1(g)
print(next(g))
print(next(g))
print(next(g))

# 用python内置函数iter()函数 把list dict str等 iterable变成iterator迭代器
fun1(iter(a))
fun1(iter(b))

在这里插入图片描述


三、匿名函数lambda

匿名函数lambda:顾名思义,没有名字的函数,可以将其赋值给一个变量。

语法:lambda [list]: 表达式

参数介绍:

"""
[list]:表示参数列表, 
注意:参数与表达式之间需要冒号来区分 
表达式 :表达式方法非常多,表达形式也非常多 
返回值 :为表达式的结果value
"""

代码实现

# -*- coding: utf-8 -*-
# @File  : 匿名函数lambda.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 10:22


fun1 = lambda a, b: x + y
x = int(input('x='))
y = int(input('y='))
print('x+y=', fun1(x, y))

fun2 = lambda a, b: a ** b

f = fun2(x, y)
print(type(fun2))
print(f"a**b= {f}")


def add(a, b):
    print('add=', a + b)


add(x, y)

在这里插入图片描述


四、高阶函数Higher-order function

1.函数式编程

   函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。

  而函数式编程——Functional Programming,虽然也可以归结到面向过程的程序设计,但其思想更接近抽象的计算。

  我们首先要搞明白计算机(Computer)和计算(Compute)的概念。
  在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。
  而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。

  对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Python语言。

  函数式编程就是一种抽象程度很高的编程范式。

  函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

  Python对函数式编程提供了部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

  • 变量可以指向函数

例如Python内置求绝对值函数abs()

>>> abs(-5)
5
>>> f = abs 
>>> f
<built-in function abs>
  可以看见,只写 abs只是函数本身,而 abs(-5)才是函数调用,实际我们如果需要函数的结果,可以将函数赋值给变量

例如:

>>> i = abs(-5) 
>>> i 
5
>>> f = abs 
>>> f 
<built-in function abs> 
>>> f(-5) 
5
  将调用函数的结果,赋值给变量 i ,这样变量就可以打印出结果,如果将函数本身赋值给变量 f ,那么变量也拥有这个函数的功能,这个变量将指向这个函数,使用变量 f ()来调用函数和直接调用 abs()效果是一样的。
  • 函数名也可以是变量
  函数是由 def定义,函数名,括号,括号参数,冒号,函数体组成,那么函数名是什么呢,可以发现, 函数名是指向函数的变量,例如 abs()这个函数,可以将 abs看成变量,它指向一个可以求绝对值的函数,如果把 abs指向其他的对象,例如我们给 abs赋值,那看看还会指向求绝对值的函数吗
>>> abs = 5 
>>> abs(-5) 
Traceback (most recent call last): 
    File "<pyshell#23>", line 1, in <module> 
      abs(-5) 
TypeError: 'int' object is not callable 
>>> abs 
5
   TypeError: 'int' object is not callable 提示,类型错误, int类型是不可以被调用的,我们看到, abs这个变量被赋值 5,然后使用 abs(-5)调动函数,发现异常,此时 abs变量指向的不是函数,而是一个 int类型的 5 ,实际上,我们工作或是开发中写代码,是不能这么写的,由此可以看出函数名其实就是变量。

注意:由于 abs 函数实际上是定义在 import builtins 模块中的,所以要让修改 abs 变量的指向在其它模块也生效可以使用。

import builtins 
builtins.abs = 10

2.引出高阶函数

  上面的例子,函数可以传参数,而函数名可以做变量,那我们函数里面的参数也可以为函数名。

代码中的total为高阶函数

# -*- coding: utf-8 -*-
# @File  : 引出高阶函数.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 10:00


def fun(i):
    return i * 2


def total(x, y, fun):
    return fun(x) + fun(y)


add_sum = total(1, 2, fun)
print(add_sum)  # 6

下面代码test称为高阶函数

# -*- coding: utf-8 -*-
# @File  : 高阶函数.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 10:12


def fac(n):   # 定义一个递归函数计算阶乘
    if n == 1:  # 递归终止条件
        return 1
    else:
        # 在test()函数的函数体内调用该本身
        return n*fac(n-1)  # 递归调用


def test(list_, fun):  # 将函数fac本身作为参数传进来,test称为高阶函数
    new_list = []
    for x in list_:
        new_list.append(fun(x))
    print(new_list)


ls = [1, 2, 3, 4, 5, 6, 7]
test(ls, fac)  # 调用函数test 并把参数lst和fac传入

3.Python内置高阶函数

# -*- coding: utf-8 -*-
# @File  : 内置高阶函数.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 14:10

from functools import reduce


'''
1.map函数:把一个可迭代对象中的每个元素转换为一个新的对象,最后返回一个新的可迭代对象'''
# map(fun, iterables)
lst = [1, 2, 3, 4, 5]
ite = map(lambda x: x ** 2, lst)
print(ite)  # <map object at 0x000002A24AF06970>
for i in ite:
    print(i, end=' ')  # 1 4 9 16 25


'''
2.reduac() 把一个可迭代对象中的每个元素都做聚合处理,返回一个聚合之后的值
from functools import reduce 
reduce(function, sequence[, initial]) -> value'''
# function:一共有两个参数的函数
# sequence:是一个序列,是一些数据的集合,或者是一组数据,可迭代对象
# initial:可选,初始参数 返回值:返回函数计算的结果
va = reduce(lambda x, y: x + y, lst)  # 求累加
print('\ns =', va)  # s = 15


def max_(x, y):
    if x > y:
        return x


max1 = reduce(max_, iter((3, 2)))  # 求最大值
print(max1)  # 3


'''
3.filter 把一个可迭代对象中的元素做过滤操作,若果func返回值为True是留下,否则过滤掉'''
staff = [
    {'name': '张三', 'age': 18, 'salary': 2000},
    {'name': '李四', 'age': 20, 'salary': 4000},
    {'name': '麻子', 'age': 22, 'salary': 6000}]

# 过滤留下大于18岁的员工
lst_age = filter(lambda x: x['age'] > 18, staff)
print('大于18岁的员工:', list(lst_age))

# 工资大于4000的员工
lst_salary = filter(lambda x: x['salary'] > 4000, staff)
print('工资大于4000的员工:', list(lst_salary))


'''
4.max 和 min'''
# 计算最大工资的员工
print('最高工资的员工:', max(staff, key=lambda x: x['salary']))
# 计算最小年龄的员工
print('最低工资的员工:', min(staff, key=lambda x: x['age']))


'''
5.sorted把一个迭代对象里的每个元素做排序,最终返回一个列表'''
# 根据员工年龄降序排序
list_sorted = sorted(staff, key=lambda x: x['age'], reverse=True)
print('工资降序排序:', list_sorted)

在这里插入图片描述


4.map 函数

map()函数,把一个可迭代对象中的每一个元素换成一个新的对象,最终返回一个迭代器

Python内置map()函数:

class map(object):
    """
    map(func, *iterables) --> map object
    
    Make an iterator that computes the function using arguments from
    each of the iterables.  Stops when the shortest iterable is exhausted.
    """
    def __getattribute__(self, *args, **kwargs): # real signature unknown
        """ Return getattr(self, name). """
        pass

    def __init__(self, func, *iterables): # real signature unknown; restored from __doc__
        pass

    def __iter__(self, *args, **kwargs): # real signature unknown
        """ Implement iter(self). """
        pass

    @staticmethod # known case of __new__
    def __new__(*args, **kwargs): # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __next__(self, *args, **kwargs): # real signature unknown
        """ Implement next(self). """
        pass

    def __reduce__(self, *args, **kwargs): # real signature unknown
        """ Return state information for pickling. """
        pass

map()函数的返回值:

map(func, *iterables) --> map object

参数详解:

"""
func:代表传入参数为函数,这里的函数指定指向函数的函数名
*iterables:代表参数指定的可迭代的
返回值:返回处理好的数据 
map()函数:是将传入的func函数作用于可迭代的数据里的面每个元素,并将处理好的新的结果返回
"""

代码实现

# -*- coding: utf-8 -*-
# @File  : map函数.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 10:03


lst = [1, 2, 3, 4, 5]
ite = map(lambda x: x**2, lst)
print(ite)  # <map object at 0x000002A24AF06970>
for i in ite:
    print(i, end=' ')
    

在这里插入图片描述


5.聚合函数reduce

reduce()函数,把一个可迭代对象中的每个元素做聚合处理,最终返回一个聚合之后的值.

functools函数reduce()

def reduce(function, sequence, initial=_initial_missing):
    """
    reduce(function, sequence[, initial]) -> value

    Apply a function of two arguments cumulatively to the items of a sequence,
    from left to right, so as to reduce the sequence to a single value.
    For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
    ((((1+2)+3)+4)+5).  If initial is present, it is placed before the items
    of the sequence in the calculation, and serves as a default when the
    sequence is empty.
    """

    it = iter(sequence)

    if initial is _initial_missing:
        try:
            value = next(it)
        except StopIteration:
            raise TypeError("reduce() of empty sequence with no initial value") from None
    else:
        value = initial

    for element in it:
        value = function(value, element)

    return value

try:
    from _functools import reduce
except ImportError:
    pass

reduce函数的参数与返回值:

注意使用reduce函数时需要先导入,reduce函数是在 functools模块里面

from functools import reduce
reduce(function, sequence[, initial]) -> value

# 参数详解
"""
function:一个有两个参数的函数 
sequence:是一个序列,是一些数据的集合,或者是一组数据,可迭代对象 
initial:可选,初始参数 
返回值:返回函数计算的结果 
reduce()函数,使用function函数(有两个参数)先对集合中的sequence第 1、2 个元素进行操作,如果存在 
initial参数,则将会以sequence中的第一个元素和initial作为参数,用作调用,得到的结果再与sequence中的 下一个数据用 function 函数运算,最后得到一个结果。
"""

代码实现:

# -*- coding: utf-8 -*-
# @File  : 聚合函数reduce.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 12:48


from functools import reduce

lst = [1, 2, 3, 4, 5]
va = reduce(lambda x, y: x+y, lst)  # 求累加
print('s =', va)


def max_(x, y):
    if x > y:
        return x


max1 = reduce(max_, iter((3, 2)))  # 比较大小求大值
print(f'max = {max1}')

在这里插入图片描述

6.过滤器filter函数

filter()函数 把一个可迭代对象中的元素做过滤操作,如果func返回值为True则留下,否则过滤掉。

Python内置的 filter() 函数用于过滤序列,和 map() 类似, filter() 也接收一个函数和一个序列,但是不同的是 filter() 把传入的函数依次作用于每个元素,然后根据返回值是 True 还是 False 决定元素的保留与丢弃。

Python内置函数filter()

class filter(object):
    """
    filter(function or None, iterable) --> filter object
    
    Return an iterator yielding those items of iterable for which function(item)
    is true. If function is None, return the items that are true.
    """
    def __getattribute__(self, *args, **kwargs): # real signature unknown
        """ Return getattr(self, name). """
        pass

    def __init__(self, function_or_None, iterable): # real signature unknown; restored from __doc__
        pass

    def __iter__(self, *args, **kwargs): # real signature unknown
        """ Implement iter(self). """
        pass

    @staticmethod # known case of __new__
    def __new__(*args, **kwargs): # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __next__(self, *args, **kwargs): # real signature unknown
        """ Implement next(self). """
        pass

    def __reduce__(self, *args, **kwargs): # real signature unknown
        """ Return state information for pickling. """
        pass
        

参数列表:

filter(function, iterable)

"""
function:判断函数。 
iterable:序列,(可迭代对象)。
 
返回值:返回列表 
filter函数,序列(可迭代对象)的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返 回 True 的元素放到新列表中
"""

filter函数实现过滤奇数:

# -*- coding: utf-8 -*-
# @File  : filter函数.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 13:06


def not_odd(num):
    return num % 2 == 0


# 过滤奇数
new_lst = filter(not_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(list(new_lst))
  这里定义了一个函数 not_odd,不是奇数的函数,这个函数,只有当参数为2的整数倍时返回 True

  这里filter函数的两个参数第一个是过滤方法,第二个是需要过滤的列表,将列表里面的元素依次带入函数中进行运算,得到的结果如果为True时,将此结果作为新的filter对象保留,等待函数里面的列表执行完成后,返回最终的值,这里的值为列表,也就是过滤掉了False的数据或元素。

filter函数过滤操作

# -*- coding: utf-8 -*-
# @File  : filter函数.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 13:06

# filter 把一个可迭代对象中的元素做过滤操作,若果func返回值为True是留下,否则过滤掉
staff = [
    {'name': '张三', 'age': 18, 'salary': 2000},
    {'name': '李四', 'age': 20, 'salary': 4000},
    {'name': '麻子', 'age': 22, 'salary': 6000}]

# 过滤留下大于18岁的员工
lst_age = filter(lambda x: x['age'] > 18, staff)
print(list(lst_age))
# 过滤留下工资大于4000的员工
lst_salary = filter(lambda x: x['salary'] > 4000, staff)
print(list(lst_salary))

在这里插入图片描述


五、返回函数

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

看代码:

# -*- coding: utf-8 -*-
# @File  : 返回函数的高阶函数.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 14:48


def sum_fun(*args):

    def add_fun():
        s = 0
        for i in args:
            s += i
        return s
    return add_fun


f = sum_fun(1, 2, 3, 4, 5, 6, 7, 8, 9)
add = f()
print(add)  # 45

当我们调用 sum_fun 时,返回的并不是求和结果,而是求和函数 add_fun , 将其赋值给f,当我们在调f函数时才返回求和结果s

filter函数来计算素数

  用 filter来计算素数其中一个方法是埃氏筛法。
  给出要筛数值的范围 n,找出以内的素数。先用 2去筛,即把 2留下,把 2的倍数剔除掉;再用下一个质数,也就是 3筛,把 3留下,把 3的倍数剔除掉;接下去用下一个质数 5筛,把 5留下,把 5的倍数剔除掉;不断重复下去......

Python高阶函数来实现这个算法:

  1. 我们先写一个生成器构造一个从3开始的无限奇数序列,首先排除偶数。
def odd_num():  # 奇数生成器函数
    n = 1
    while True:
        n += 2
        yield n
  1. 写一个筛选的函数,这里使用了匿名函数,返回判断是否为可整除数
def un_divisible(n):  # 判断是否为可整除数
    return lambda x: x % n > 0
  1. 使用filter来过滤,不断返回素数的生成迭代
def primes():  # 素数生成器函数
    yield 2
    it = odd_num()
    while True:
        n = next(it)
        yield n
        it = filter(un_divisible(n), it)  # 过滤出不可以整除的数
  1. 判断素数方法就产生了,这里需要手动结束一下
for i in primes():  # 打印小于100的素数
    if i < 100:
        print(i)
    else:
        break  

高阶函数实现打印小于100的素数:

# -*- coding: utf-8 -*-
# @File  : 返回函数计算质数.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 15:17


# 得到所有的质数,打印小于100的所有的质数
# 最小的质数是2, 质数:只能被1和它本身整除的数
# 思路:先得到所有大于1的奇数, --> 生成器,在把生成器中的所有元素过滤去掉: 那些可以被小于元素本身的质数整除的数


# 1.得到所有的大于1奇数的生
def odd_num():
    n = 1
    while True:
        n += 2
        yield n


def un_divisible(n):  # 判断是否能够整除的函数,n代表从生成器中拿到的一个大于1的质数
    return lambda x: x % n > 0  # x是某一个奇数,n:小于当前x的一个质数


# 2.创建一个质数的生成器,最小的质数是2
def primes():
    yield 2
    n = odd_num()  # g为大于1的奇数生成器
    while True:
        x = next(n)
        g = filter(un_divisible(n), n)
        yield x


for i in primes():
    if i < 100:
        print(i, end=' ')
    else:
        break
第一段代码生成了以3开始的奇数序列
第二段代码自定义过滤函数,包含匿名函数,判断值的取余是否能被整除
第三段代码用来返回素数,这里先返回一个2为素数,因为偶数都被排除了所

这就是100以内的所有素数:
在这里插入图片描述


六、闭包

1.什么是闭包

  什么是闭包:一个函数定义中引入了函数定义以外的变量,并且该函数可以在其定义以外被执行,这个函数以及引用到外部的变量称为闭包。

闭包的三个条件,缺一不可

"""
1)必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套 

2)内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量

3)外部函数必须返回内嵌函数——必须返回那个内部函数
"""

闭包代码实现:

# -*- coding: utf-8 -*-
# @File  : 闭包.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 15:58


# 定义一个函数
def fun_a(num_a):
    # 在函数内部再定义⼀个函数
    # 并且这个内部函数⽤到了外部的变量,这个函数以及⽤到外部函数的变量及参数叫 闭包
    def fun_b(num_b):
        print('内嵌函数fun_b的参数是:%s,外部函数fun_a的参数是:%s' % (num_b, num_a))
        return num_a + num_b
    # 这里返回的就是闭包的结果
    return fun_b


# 给fun_a函数赋值,这个10就是传参给fun_a
ret = fun_a(10)

# 注意这里的10其实是赋值给fun_b
print(ret(10))

# 注意这里的90其实是赋值给fun_b
print(ret(90))

在这里插入图片描述

  此时,内部函数对外部函数作⽤域⾥变量的引⽤(⾮全局变量),则称内部函数为闭包。

2.闭包修改外部变量

python交互环境idle

>>> def counter(start = 0):
    count = [start]
    def incr():
        count[0] += 1
        return count[0]
    return incr

>>> c1 = counter(5)
>>> print(c1())
6
>>> print(c1())
7
>>> print(c2())
51
>>> print(c2())
52
>>>
  当一个函数在本地作用域找不到变量申明时会向外层函数寻找,这在函数闭包中很常见但是在本地作用域中使用的变量后,还想对此变量进行更改就会报错。

看一段代码:

# -*- coding: utf-8 -*-
# @File  : 闭包修改外部变量.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 16:30


# 闭包修改外部变量的值
def test1():
    c = 1
    # c不是局部变量,是介于局部变量和全局变量之间的一种变量,用 nonlocal标识

    def add1():

        print(c)  # 1
        c += 1
        return c  # 2
    return add1


print(test1()())

报错信息:
在这里插入图片描述

此时,如果我在函数内加一行nonlocal c就可解决这个问题

代码:

# -*- coding: utf-8 -*-
# @File  : 闭包修改外部变量.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 16:30


# 闭包修改外部变量的值
def test1():
    c = 1
    # c不是局部变量,是介于局部变量和全局变量之间的一种变量,用 nonlocal标识

    def add1():
        nonlocal c
        print(c)  # 1
        c += 1
        return c  # 2
    return add1


print(test1()())

nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量(介于局部变量和全局变量之间的一种变量)。

使用 nonlocal的好处是,在为函数添加状态时不用额外地添加全局变量,因此可以大量地调用此函数并同时记录着多个函数状态,每个函数都是独立、独特的。

3.闭包的应用

闭包实现 y = a*x + b

# -*- coding: utf-8 -*-
# @File  : 闭包的应用.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 16:18


# y = a*x + b
def create_line(a, b):
    def line(x):
        return a * x + b

    return line


line1 = create_line(1, 1)  # a:1 b:1
line2 = create_line(4, 5)  # a:4 b:5

print(line1(5))  # 6
print(line2(5))  # 25
从这段代码中,函数 line与变量 a,b构成闭包。在创建闭包的时候,我们通过 create_line的参数 a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式( y = x + 1y = 4x + 5)。我们只需要变换参数 a,b,就可以获得不同的直线表达函数。

由此,我们可以看到,闭包也具有提⾼代码可复⽤性的作⽤。

如果没有闭包,我们需要每次创建函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。

1.闭包优化了变量,原来需要类对象完成的⼯作,闭包也可以完成
2.由于闭包引⽤了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

4.闭包的陷阱

  函数内部函数,引用外部函数参数或值,进行内部函数运算执行,并不是完全返回一个函数,也有可能是一个在外部函数的值,我们还需要知道返回的函数不会立刻执行,而是直到调用了函数才会执行。

看代码:

# -*- coding: utf-8 -*-
# @File  : 闭包的陷阱.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 17:09


def fun_a():
    fun_list = []
    for i in range(1, 4):

        def fun_b():
            return i * i

        fun_list.append(fun_b)
    return fun_list


f1, f2, f3 = fun_a()
print(f1(), f2(), f3())  
# 9 9 9 
  这里创建了一个 fun_a函数,外部函数的参数 fun_list定义了一个列表,在进行遍历,循环函数 fun_b,引用外部变量i 计算返回结果,加入列表,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了,但是实际结果并不是我们想要的 1, 4, 9,而是 999,这是为什么呢?

  这是因为,返回的函数引用了变量 i ,但不是立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,每一个独立的函数引用的对象是相同的变量,但是返回的值时候,3个函数都返回时,此时值已经完整了运算,并存储,当调用函数,产生值不会达成想要的,返回函数不要引用任何循环变量,或者将来会发生变化的变量,但是如果一定需要呢,如何修改这个函数呢?

我们fun_b()把这里的参数i赋值给x就可以解决

# -*- coding: utf-8 -*-
# @File  : 闭包的陷阱.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 17:09


def fun_a():
    fun_list = []
    for i in range(1, 4):

        def fun_b(x=i):
            return x ** 2

        fun_list.append(fun_b)
    return fun_list


f1, f2, f3 = fun_a()
print(f1(), f2(), f3())  
# 1 4 9
  可以再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变,那我们就可以完成下面的代码:
# -*- coding: UTF-8 -*- # 
def fun_a(): 
    def fun_c(i): 
        def fun_b(): 
            return i * i 
            
        return fun_b 

    fun_list = [] 
    for i in range(1, 4): 
        # f(i)立刻被执行,因此i的当前值被传入f() 
        fun_list.append(fun_c(i)) 
    return fun_list 


f1, f2, f3 = fun_a() 
print(f1(), f2(), f3()) 
# 1 4 9

七、装饰器

1.什么是装饰器

先看一段代码:

# -*- coding: utf-8 -*-
# @File  : 什么是装饰器.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 19:38


def fun():
    print('洗脸')


fun()  # 调用fun函数
# 洗脸


# 想给fun函数增加 起床 和 吃早点 这两个功能
def test1(func):
    def test2():
        print('起床')
        func()
        print('吃早点')
    return test2


test1(fun)()
# 起床
# 洗脸
# 吃早点
  由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。也可以将函数赋值变量,做参传入另一个函数。
  装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值 也是一个函数对象。

  它经常用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。

2.装饰器的作用

装饰器的作用:为已经存在的对象添加额外的功能

看代码代码:

# -*- coding: utf-8 -*-
# @File  : 装饰器.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 19:46


def test1(func):
    def test2():
        print('起床')
        func()
        print('吃早点')
    return test2


@test1  # 装饰器
def fun():
    print('洗脸')


fun()
# 起床
# 洗脸
# 吃早点
  我们没有直接将 fun函数作为参数传入 test1中,只是将 test1函数以@方式装饰在 fun函数上。

  也就是说,被装饰的函数,函数名作为参数,传入到装饰器函数上,不影响fun函数的功能,再此基础上可以根据业务或者功能增加条件或者信息。

(注意:@在装饰器这里是作为Python语法里面的语法糖写法,用来做修饰。)

  但是我们这里就存在一个问题,这里引入魔术方法 __name__ ,这是属于 python 中的内置类属性,它天生就存在于一个 python 程序中,代表对应程序名称,一般一段程序作为主线运行程序时其内置名称就是 __main__ ,当自己作为模块被调用时就是自己的名字。
print(fun.__name__)
# test2
  这并不是我们想要的!输出应该是 fun,这里的函数被 test2替代了。它重写了我们函数的名字和注释文档,那怎么阻止变化呢,Python提供 functools模块里面的 wraps函数解决了问题。

代码实现:

# @Time  : 2022/8/21 20:04

from functools import wraps


def test1(func):
    @wraps(func)  # 使用fun来包装test2
    def test2():
        print('起床')
        func()
        print('吃早点')
    return test2


@test1  # 装饰器
def fun():
    print('洗脸')


fun()
print(fun.__name__)  # fun

在这里插入图片描述

我们在装饰器函数内,作用 funtest2函数上也增加了一个装饰器 wraps还是带参数的,这个装饰器的功能就是不改变使用装饰器原有函数的结构。

3.装饰器记录日志功能

work()函数增加记录日志功能

# -*- coding: utf-8 -*-
# @File  : 装饰器实现记录日志功能.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 20:09

import time
from functools import wraps


def log(fun):
    @wraps(fun)
    def write_log():
        print("[info]--时间是:%s" % time.strftime("%Y-%m-%d %H:%M:%S"))
        fun()
    return write_log


@log
def work():
    print("我在学习Python")


work()

在这里插入图片描述

4.带参装饰器

  我们也看到装饰器 wraps也是带参数的,那我们是不是也可以定义带参数的装饰器呢,我们可以使用一个函数来包裹装饰器,调入这个参数。
# -*- coding: utf-8 -*-
# @File  : 带参数的装饰器.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 21:01

import time
from functools import wraps


def logs(func):
    @wraps(func)
    def write_log(*args, **kwargs):
        print('[info]--时间:%s' % time.strftime('%Y-%m-%d %H:%M:%S'))
        func(*args, **kwargs)
    return write_log


@logs
def work():
    print('我在工作')


@logs
def work2(name1, name2):
    print('%s和%s在工作' % (name1, name2))


work2('张三', '李四')
# [info]--时间:2022-06-24 18:04:04
# 张三和李四在工作

在这里插入图片描述


5.函数做装饰器

把日志写入文件

# -*- coding: utf-8 -*-
# @File  : 把日志写入文件.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 21:14

import time
from functools import wraps


def logger(log_file):
    def logs(fun):
        @wraps(fun)
        def write_log(*args, **kwargs):
            log = "[info]--时间是:%s" % time.strftime('%Y-%m-%d %H:%M:%S')
            print(log)
            with open(log_file, 'a+') as f:
                f.write(log+'\n')
            fun(*args, **kwargs)
        return write_log
    return logs


@logger('work.log')  # 使用装饰器来给 work函数增加记录日志的功能
def work(name1, name2):  # 1.当前 work可能有多个参数 2.自定义日志文件的名字和位置,记录日志级别
    print(f"{name1}和{name2}正在工作")


work('张三', '李四')

终端输出:
在这里插入图片描述
work.log文件记录日志
在这里插入图片描述

  这里我们将带参数的带入进去根据代码流程执行生成了文件并将日志信息打印进去现在我们有了能用于正式环境的 logger装饰器,但当我们的应用的某些部分还比较脆弱时,异常也许是需要更紧急关注的事情。

6.类做装饰器

# -*- coding: utf-8 -*-
# @File  : 把日志写入文件.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 21:14

import time
from functools import wraps


class Log(object):
    def __init__(self, log_file, level="INFO"):
        self.log_file = log_file
        self.level = level

    def __call__(self, fun):  # 定义装饰器,需要有一个接受函数
        @wraps(fun)
        def write_log(*args, **kwargs):
            log = "[%s]--时间是:%s" % (self.level, time.strftime('%Y-%m-%d %H:%M:%S'))
            print(log)
            with open(self.log_file, 'a+') as f:
                f.write(log+'\n')
            fun(*args, **kwargs)
        return write_log


@Log('work3.png')
def learn(name):
    print(f"{name}在学习Python")


@Log('work2.log')  # 使用装饰器来给 work函数增加记录日志的功能
def work(name1, name2):  # 1.当前 work可能有多个参数 2.自定义日志文件的名字和位置,记录日志级别
    print(f"{name1}和{name2}正在工作")


learn("Flyme awei")
work('张三', '李四')

在这里插入图片描述

  类实现装饰器有一个优势,在于比嵌套函数的方式更加整洁,而且包裹一个函数还是使用跟以前一样的语法。

八、偏函数Partial function

  Python的 functools 模块提供了很多有用的功能,其中一个就是偏函数( Partial function)。要注意,这里的偏函数和数学意义上的偏函数不一样。
  例如: int() 函数可以把字符串转换为整数,当仅传入数字字符串时, int() 函数默认按十进制转换
>>> int('123') 
123
  但 int() 函数还提供额外的 base 参数,默认值为 10 。如果传入 base 参数,就可以做进制的转换。
>>> int('12345', base=8) 
5349 
>>> int('12345', 16) 
74565
  如果要转换大量的二进制字符串,每次都传入 int(x, base=2) 非常麻烦,于是,我们想到,可以定义一个 int2() 的函数,默认把 base=2 传进去:

代码:

# 定一个转换义函数 
def int_bin(num, base=2):
    return int(num, base=2)


print(int_bin('1001'))  # 9
  把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单,继续优化, functools.partial 就是帮助我们创建一个偏函数的,不需要我们自己定义 int_bin() 函数,可以直接使用下面的代码创 建一个新的函数。
# -*- coding: utf-8 -*-
# @File  : 偏函数partial.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 22:18

from functools import partial


int2 = partial(int, base=2)
print(int2('1001'))  # 9
  理清了 functools.partial 的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

  注意到上面的新的 int2 函数,仅仅是把 base 参数重新设定默认值为 2 ,但也可以在函数调用时传入其他值实际上固定了int()函数的关键字参数 base


九、总结

1.生成器

   ⽣成器是这样⼀个函数,它记住上⼀次返回时在函数体中的位置。对⽣成器函数的第⼆次(或第 n 次)调⽤跳转⾄该函数中间,⽽上次调⽤的所有局部变量都保持不变。

  ⽣成器不仅记住了它数据状态;⽣成器还记住了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。

2.迭代器

  迭代器是访问集合的一种方式,可以记住遍历位置的对象,迭代器从集合的第一个元素开始访问,直到所有的元素被访问完才结束,只能往往前,不能后退。

3.匿名函数

匿名函数 lambda:顾名思义,没有名字的函数,可以将其赋值给一个变量。
语法: lambda 参数列表: 表达式

4.内置高阶函数

函数 说明
map(func, *iterables) 创建一个迭代器,使用from的参数计算函数每个可迭代对象。当最短的可迭代对象耗尽时停止。
reduce(function, sequence[, initial]) 对序列中的项累计应用两个参数的函数,从左到右,从而将序列缩减为单个值。
filter(function or None, iterable) 返回一个迭代器,返回iterablefunction(item)对应的元素是真的。如果functionNone,则返回为true的项。
max() 返回其最大的项
min() 返回其最小的项
sorted() 返回一个新列表,其中包含可迭代对象中的所有项,按升序排列。

5.返回函数

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

6.闭包

  一个函数定义中引入了函数定义以外的变量,并且该函数可以在其定义以外被执行,这个函数以及引用到外部的变量称为闭包。

7.装饰器

  装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值 也是一个函数对象。

  它经常用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。

8.偏函数

  Python的 functools 模块提供了很多有用的功能,其中一个就是偏函数( Partial function)。
相关实践学习
基于函数计算一键部署掌上游戏机
本场景介绍如何使用阿里云计算服务命令快速搭建一个掌上游戏机。
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
相关文章
|
16小时前
|
存储 数据处理 Python
python 之map、zip和filter迭代器示例详解
python 之map、zip和filter迭代器示例详解
7 0
|
1天前
|
存储 程序员 Python
深入理解Python中的生成器和迭代器
本文将深入探讨Python中生成器和迭代器的概念、原理以及它们在编程中的应用。通过详细解析生成器和迭代器的工作机制,读者将能够更好地理解Python中的迭代器协议、生成器函数以及生成器表达式的使用方法。同时,本文还将介绍生成器和迭代器在Python中的一些常见应用场景,并提供一些实用的编程技巧和最佳实践。
|
2天前
|
存储 Python 容器
Python高级编程
Python集合包括可变的set和不可变的frozenset,用于存储无序、不重复的哈希元素。创建集合可使用{}或set(),如`my_set = {1, 2, 3, 4, 5}`。通过add()添加元素,remove()或discard()删除元素,如`my_set.remove(3)`。
|
10天前
|
Python 容器
python匿名函数、迭代器、高阶函数(二)
python匿名函数、迭代器、高阶函数(二)
|
10天前
|
索引 Python
python匿名函数、迭代器、高阶函数(一)
python匿名函数、迭代器、高阶函数(一)
|
10天前
|
容器
【Python21天学习挑战赛】-迭代器 & f-格式化 & 模块
【Python21天学习挑战赛】-迭代器 & f-格式化 & 模块
|
13天前
|
存储 Python
深入理解Python中的生成器和迭代器
本文将深入探讨Python中生成器和迭代器的概念及其在实际编程中的应用。通过对生成器和迭代器的原理解析,以及实际案例的演示,读者将能够更好地理解和利用这些强大的编程工具。
|
14天前
|
运维 Shell Sentinel
第八章 Python可迭代对象、迭代器和生成器
第八章 Python可迭代对象、迭代器和生成器
|
15天前
|
数据采集 存储 大数据
Python中的迭代器与生成器
Python中的迭代器与生成器
14 0
|
22天前
|
缓存 大数据 数据处理
Python迭代器、生成器和装饰器探究
【4月更文挑战第2天】 迭代器是遍历集合元素的对象,实现`__iter__()`和`__next__()`方法。示例中自定义迭代器`MyIterator`用于生成整数序列。 - 生成器简化了迭代器实现,利用`yield`关键词实现状态保存,减少内存占用。示例中的`my_generator`函数即为一个生成器。 - 装饰器用于修改函数行为,如日志记录、性能分析。装饰器`my_decorator`在函数调用前后添加额外代码。
29 0