Py高级函数

7.1 闭包

        如果在一个内部函数中对外部函数作用域(非全局作用域)的变量进行引用,那么内部函数就会被称为闭包。满足闭包条件:

  1. 存在于嵌套关系的函数中
  2. 嵌套在内部函数引用了外部函数的变量
  3. 嵌套的外部函数会将内部函数名作为返回值返回
# 外部函数
def outer(start = 0):
    count = [start]		# 函数内的变量
    def inner():
        count[0] += 1	# 引用外部函数的变量
        return count[0]
    # 返回内部函数的名称
    return inner

quote = outer(5)
print(quote())			# 引用 quote() 函数实际上调用 inner() 函数

请添加图片描述

请添加图片描述

  1. 调用 outer 函数,将 5 传给 start 参数
  2. count 存放 5
  3. 返回内部函数 inner
  4. 将调用 outer 函数返回的 inner 赋值给 quote 变量,即 quote = inner 。此时,quote 变量引用的是 inner 函数占用的内存空间。
  5. 调用 quote 引用的函数 相当于调用 inner 函数。此时,程序来到 inner 函数的定义部分
  6. coute + 1 计算结果再次赋值为列表的元素,此时列表中存放 6
  7. 返回 count 列表的元素值 6

        从内部函数的定义看,在 count 函数执行结束后,变量 count 已被销毁。当 outer 函数执行完后,又会执行内部的 inner 函数,由于 inner 函数使用了 count 变量,此时程序为啥没报错?

        主要是函数的闭包会记得外层函数的作用域,在 inner 函数(闭包)中引用了外部函数的 count 变量,所以程序不会释放这个变量。

7.2 装饰器

7.2.1 What

        装饰器可以在不改动其他函数的前提下,对函数的功能进行扩充。用于场景:

  1. 引入日志
  2. 函数执行的时间统计
  3. 执行函数前准备处理
  4. 执行函数后清理功能
  5. 权限校验
  6. 缓存
def print_log(func):
    print('函数正在运行中')
    func()
def func():
    print('test')
print_log(test)

        定义一个打印日志函数虽然实现了该功能,但破坏了原有代码的逻辑结构。如果要求实现的函数不能修改,只能扩展。即遵循“封闭开放”原则。

        装饰器即可满足此条件。以 @ 开头

def wrap(func):
    print("正在装饰")

    def inner():
        print('正在验证权限')
        func
        
    return inner

@wrap
def test():
    print('test')

test()

请添加图片描述

  1. 执行 test() 时,发现该函数上面有装饰器 @wrap 会先执行 @wrap 等价于 test = wrap(test)

    • 执行 wrap(test) ,将函数名 test 作为参数传给 wrap 。在调用 wrap 函数时,会先执行 print 语句,输出 “正在装饰”, 然后会将形参 func 指向 test() 函数体,并将 inner函数 的引用返回给 wrap(test) 作为 wrap(test) 的返回值

    请添加图片描述

    • wrap(test) 的返回值赋给 test ,此时 test 指向 inner() 函数,完成了函数test() 的装饰

      请添加图片描述

  2. 调用 test() 指向的函数。因为 test 指向 inner()函数 ,所以此时,调用 test()函数 相当于调用 inner()函数,输出过程如下:

    • 输出 print 语句 “正在验证权限”
    • 调用 func 指向的函数,输出 “test”

7.2.2 多个装饰器

        多个装饰器可以应用在一个函数中,调用顺序自下而上。

def wrap_one(func):
    print("--正在装饰器1--")
    def inner():
        print('--正在验证权限1--')
        func()
    return inner

def wrap_two(func):
    print("--正在装饰器2--")
    def inner():
        print('--正在验证权限2--')
        func()
    return inner

@wrap_one
@wrap_two
def test():
    print("---test---")
# 调用 test 之前,已经装饰过了
test()
  1. 程序将 wrap_one wrap_two test 函数加载到内存中

请添加图片描述

  1. test() 函数有两个装饰器,首先执行 @wrap_two

    请添加图片描述

  2. 执行 @wrap_one 也就是 test = wrap_one(test) ,执行完毕后会输出:

    --正在装饰2--
    --正在装饰1--
    

请添加图片描述

  1. 装饰完毕后,如果使用 test() 语句调用 test 函数,程序按照从上向下的顺序执行输出:

    --正在验证权限1--
    --正在验证权限2--
    --test--
    

7.2.3 装饰器对有参数函数进行装饰

        有参

def wrap(func):
    # inner 传参
    def inner(a, b):
        print("开始验证权限")
        # func 传参
        func(a, b)
    return inner

@wrap
def test(a, b):
    print('a = %d, b = %d' %(a, b))

test(1, 2)
开始验证权限
a = 1, b = 2

        不定长参数

def wrap(func):
    def inner(*args, **kwargs):
        print("开始验证权限")
        func(*args, **kwargs)
    return inner

@wrap
def test(*args, **kwargs):
    print('--test--')

test(1, 2,3)
test(a = 1, b = 2,c = 3)
开始验证权限
--test--
开始验证权限
--test--

7.2.4 装饰器对带有返回值的函数进行装饰

def func(function_name):
    def func_in():
        return function_name()
    return func_in

@func
def test():
    return 'itheima'

result = test()
print(result)

7.2.5 带有参数的装饰器

        如果我们给装饰器添加参数,那么需要增加一层封装,先传参,然后在传递函数名。

def func_arg(args):
    def func(function_name):
        def func_in():
            print('--记录日志-args = %s'%args)
            function_name()
        return func_in
    return func

@func_arg('Link')	
def test():
    print('--test--')

test()
--记录日志-args = Link
--test--

        @func_arg('Link') 等价于 test = func_arg('Link')(test)

        由于函数 func_args 的返回值是 func 函数的引用,也就是函数名 func ,等价于 test = func(test)

        相比无参的装饰器,带有参的装饰器只是用来“加强装饰”的,如果希望装饰器可以根据参数的不同,对不同的函数进行不同的装饰,可以优先使用带参的装饰器

7.3 常见 Python 内置函数

7.3.1 map 函数

        map 函数会根据提供的函数对指定的序列做映射

map(function, iterable, ...)
  • function: 函数名

  • iterablr: 可以是序列、支持迭代的容器或迭代器。

  • 调用 map 时,iterable 中的每一个元素都会调用 function 函数,所有元素调用 function 函数返回的结果会保存到一个迭代器对象中。

  • 可以通过 list 函数进行转换成 列表 也可通过 for 循环直接遍历迭代器对象,可以取出其内部的每个元素。

    func = lambda x:x+2
    result = map(func, [1, 2, 3, 4, 5])
    print(list(result))
    

请添加图片描述

  • 如果 map 函数传入的 function 带有俩参数,map 也需要传递两个序列

    result = map(lambda x, y: x+y, [1,2,3],[4,5,6])
    print(list(result))
    # 结果为
    [5, 7, 9]
    

7.3.2 filter 函数

        filter: 会对指定序列执行过滤操作

filter(function, iterable)
  • function 可以是函数名,也可以是None。函数只能接收一个参数,返回值为布尔值。
  • **iterablr : ** 可以是序列、支持迭代的容器或迭代器。返回值位迭代器对象。

        filter 函数的作用是以参数迭代器中的每个元素分别调用 function 函数,最后返回的迭代器包含调用结果为 True

func = lambda x : x & 1
res = filter(func, [1, 2, 3, 4, 5])
print(list(res))
# 结果为
[1, 3, 5]

        定义一个匿名函数 func, 返回某个数取余以后的结果,接着调用 filter 函数将**[1, 2, 3, 4, 5]** 中的每个元素取出来,作为 func 的参数调用 func函数 之后转换成列表的形式显示。

请添加图片描述

        序列把原始序列的元素执行取余操作后,得到不能被 2 整除(结果为 True)的元素筛选出来构成新的列表。

7.3.3 reduce 函数

        reduce 函数对参数迭代器中的元素进行累积。

functools,reduce(function, iterable[, initializer])
  • function: 是带有两个参数的函数
  • iterable: 迭代器对象
  • initializer: 表示固定的初始值

        reduce函数 会依次从迭代器对象中取出每一个元素,和上次调用 function 的结果作为参数再次调用 function函数

        reduce 函数被放置在 functools 模块中,使用时先导入

from functools import reduce

func = lambda x, y: x + y
res = reduce(func, [1,2,3,4,5])
print(res)
# 结果为
15

        调用 reduce 函数是传入了 func序列, 所以程序将列表的每个元素取出来和上次调用后的结果作为参数再次调用 func 函数,最后返回给 res.

        iterable 参数也可以传入字符串类型.function 不能为None.

ret = reduce(lambda x, y: x+y, ['aa', 'bb', 'cc'], 'dd')
print(ret)
# 结果为
ddaabbcc

     调用 reduce 函数是传入了 func序列, 所以程序将列表的每个元素取出来和上次调用后的结果作为参数再次调用 func 函数,最后返回给 res.

        iterable 参数也可以传入字符串类型.function 不能为None.

ret = reduce(lambda x, y: x+y, ['aa', 'bb', 'cc'], 'dd')
print(ret)
# 结果为
ddaabbcc
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值