Python函数介绍(三)

1. 高阶函数

1.1 基本概念

  • 什么是高阶函数
    接收函数作为参数,或者将函数作为返回值返回的函数就是高阶函数。
  • 高阶函数有什么好处
    当使用函数作为参数时,实际上是将指定的代码传递到目标函数。

示例代码
定义一个函数:根据不同的需求筛选列表中的元素。

# 判断是否是偶数
def fn1(n):
    if n % 2 == 0:
        return True
    return False

# 判断是否大于5
def fn2(n):
    if n > 5:
        return True
    return False

# 定义待筛选的列表
lst = list(range(1, 11))
# 定义一个高阶函数
def function(fn_args, lst):
    # 创建一个新的列表
    new_lst = []
    # 参数lst表示待筛选的列表
    # 参数fn_args表示传递的函数对象,该函数对象就是想要的筛选规则
    for i in lst:
        if fn_args(i):
            new_lst.append(i)
    return new_lst
# 传递函数参数的时候不要加括号,加括号表示调用函数
r = function(fn1, lst)
print('筛选列表中的偶数:', r)
r = function(fn2, lst)
print('筛选列表中大于5的数:', r)

运行结果:

在这里插入图片描述

1.2 匿名函数

  • 关于 filter() 函数
    filter() 函数可以对序列进行一个过滤。
    filter() 函数的返回值是一个 filter 对象。
  • filter() 函数的参数
    参数1——function(),表示函数对象。
    参数2——iterable,表示可迭代对象(例如序列)。

示例代码

# 判断是否是偶数
def fn1(n):
    if n % 2 == 0:
        return True
    return False
    
lst = list(range(1, 11))
# filter()是高阶函数的一种,参数中传递了一个函数对象
r = filter(fn1, lst)
print('filter的返回值:', r)
r = list(filter(fn1, lst))
print('筛选列表中的偶数:', r)

运行结果:

在这里插入图片描述

  • lambda 表达式
    可以用来创建一些简单的函数,它是函数的另一种创建方式。
    lambda 表达式的语法:

lambda 参数列表 : 返回值

示例代码

# 定义两数求和的匿名函数
print(lambda a, b : a + b)
# 将lambda表达式赋值给函数变量
fn = lambda a, b : a + b
# 调用匿名函数
a = 123
b = 456
r = fn(a, b)
print(f'{a} + {b} = {r}')

运行结果:

在这里插入图片描述

使用 lambda 表达式的好处:减少内存消耗。定义函数的内存开销较大,对于一些功能很简单的函数,建议使用 lambda 表达式,也有利于后期程序的优化。

1.3 闭包

将函数作为返回值也是高阶函数,我们也称其为闭包。
示例代码:

# 返回值为函数
def func():
	a = 10
    # 函数内部定义一个函数
    def fn1():
        print('我是fn1', a)
    # 返回函数不需要加括号
    return fn1

# 打印的是func函数的返回值
print('func()的返回值: ', func())
# 变量接收func的返回值, r是一个函数对象
r = func()
# 调用函数,这样才能打印‘我是fn1’
r()

运行结果:

在这里插入图片描述

闭包的好处:通过闭包可以创建⼀些只有当前函数能访问的变量,可以将⼀些私有数据藏到闭包中。

示例代码:

# 定义一个函数求多个数的平均数
lst = []
def fn(n):
    # 参数n表示添加到列表中的数
    lst.append(n)
    # 求平均数
    return sum(lst)/len(lst)

print(fn(10)) # lst=[10] 10 / 1 = 10
print(fn(10)) # lst=[10, 10] (10 + 10) / 2 = 10
print(fn(50)) # lst=[10, 10, 50] (10 + 10 + 50) / 3 = 23.333

运行结果:

在这里插入图片描述

上述代码中定义的 lst 是全局列表,如果在其他地方不小心修改了这个列表,会影响当前代码的功能实现,非常不安全。
使用闭包:

# 定义一个函数求多个数的平均数
def make_func():
    # 闭包形成条件:函数嵌套
    lst = []
    def fn(n):
        # 参数n表示添加到列表中的数
        # 闭包形成条件:内部函数必须要使⽤到外部函数的变量
        lst.append(n)
        # 求平均数
        return sum(lst)/len(lst)
    # 闭包形成条件:将内部函数作为返回值
    return fn
# 变量f接收函数对象
f = make_func()
# 验证结果
print(f(10))
print(f(10))
# 清空lst列表
lst = []
print(f(50))

运行结果:

在这里插入图片描述
形成闭包的条件:

  1. 函数嵌套;
  2. 将内部函数作为返回值返回;
  3. 内部函数必须要使用到外部函数的变量。

2. 装饰器

2.1 引入装饰器

我们可以直接通过修改函数中的代码去完成相应的需求,但是会产生一些问题:

  1. 如果要修改的函数较多,修改起来比较麻烦;
  2. 不方便后期维护;
  3. 这种方式违反开闭原则(ocp),要求对开发程序的扩展,要求关闭程序的修改。
# 定义一个功能简单的函数
def add(a, b):
    return a + b
# 希望在不修改原函数的前提下,对原函数进行扩展
def new_add(a, b):
    print('计算开始了。。。')
    print(f'{a}+{b} = {add(a, b)}')
    print('计算结束了。。。')
# 调用新函数
new_add(45, 87)

运行结果:

在这里插入图片描述

上述代码没有违反ocp原则,也对原函数进行扩展。但上述代码的缺陷在于:只能扩展一个函数,且想要扩展新的函数,必须得继续添加代码。
在这样的背景下,有没有通用的方法对函数进行扩展?装饰器的作用就是提供通用的函数扩展方法。

2.2 装饰器的使用

直接上示例代码

# 定义功能简单的函数
def add(a, b):
    return a + b
def fn():
    print('我是函数fn')

# 用来对其他函数进行扩展,扩展的功能是 添加两个print语句,显示函数的开始与结束
def start_end(old):
    # 参数old表示要扩展的函数
    # 创建新函数, 使用不定长参数保证通用性
    def new_func(*a, **b):
        print('函数开始了。。。')
        # 定义变量接收old函数的返回值
        result = old(*a, **b)
        print('函数结束了。。。')
        return result
    # 返回上述函数
    return new_func

# 扩展add函数
f = start_end(add)
# 调用函数
print(f(35, 78))
# 扩展fn函数
f = start_end(fn)
print(f())

运行结果:
在这里插入图片描述

类似于上述代码中的 start_end() 的一类函数就称之为装饰器。
通过装饰器,可以在不修改原函数的前提下,对其他函数进行扩展。
在实际开发中,都是通过装饰器来对函数进行扩展。

但上述并非是装饰器的常用写法,更加通用的写法如下:

def start_end(old):
    # 参数old表示要扩展的函数
    # 创建新函数, 使用不定长参数保证通用性
    def new_func(*a, **b):
        print('函数开始了。。。')
        # 定义变量接收old函数的返回值
        result = old(*a, **b)
        print('函数结束了。。。')
        return result
    # 返回上述函数
    return new_func
# 通过@使用装饰器
@start_end
def speak():
    print('这是使用装饰器对speak函数进行扩展的测试')
speak()

运行结果:

在这里插入图片描述

3. 命名空间

  • locals() 来获取当前作用域的命名空间,返回的是一个字典。
  • 向命名空间中添加了key-value,相当于在全局空间中创建了一个变量。
a = 10
def fn():
    print('我是函数fn')
scope = locals()
print(scope)
print(scope['a'])
# 添加key-value
scope['c'] = 123
print(c)

运行结果:

在这里插入图片描述

上述操作并不推荐使用,仅作为一个知识点的介绍。

  • 如果在局部命名空间中添加了key-value,是无法创建局部变量的。
def fn():
    a = 456
    scope = locals()
    scope['c'] = 123
    print(scope)
    print(c)
fn()

运行结果:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值