Python基础 day09--函数进阶

摘要由CSDN通过智能技术生成

匿名函数

匿名函数的目的就是要没有名字,给匿名函数赋予一个名字是没有意义的;

匿名函数的参数规则、作用域关系和有名函数是一样的

匿名函数的函数体通常应该是一个表达式,该表达式必须要有一个返回值。

Python的匿名函数   lambda 参数:函数体
print((lambda x,y:x+y)(12,4))
# 结果为:
16

filter()函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。

a = [1, 2, 3, 4, 5, 6]
def func(x):
    return x % 2 ==0

print(list(filter(func,a)))
# 结果为:
[2, 4, 6]

print(list(filter(lambda x:x%2 == 0,a)))
# 结果为:
[2, 4, 6]

高阶函数

高阶函数:

1. 形参为函数的函数

2.返回值为函数的函数

以上条件,只要能满足其一,我们就称这个函数为高阶函数

在Python中,一切皆为数据,函数亦是变量,只能函数是比较特殊的变量,需要+() 可调用的变量。

闭包

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

简单的来说,就是一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行。这样的一个函数我们称之为闭包。实际上闭包可以看做一种更加广义的函数概念。因为其已经不再是传统意义上定义的函数。

def func():
    x = 10
    def inner():

        print(x)

    return  inner
fun1 = func()
func()

闭包:内层函数如果应用的外层的自由变量,那这个时候python解释器会帮你把x = 10 继续保存着,让内层函数继续调用。我们称这种函数叫做闭包函数。

如示例中func()中的内层函数inner()就是闭包函数。
闭包作用:保存外层函数的变量,不被回收。

 

开放封闭原则

在说装饰器之前,我们还要学习一个原则——开放封闭原则。那什么是开放封闭原则呢?

对扩展是开放的

为什么要对扩展开放呢?可以想象一下,任何一个程序在设计之初,都不可能做到面面俱到、实现所有的功能,并且后续不作任何更改。所以,我们要支持代码扩展,添加新的功能。

对修改是封闭的

既然说要允许代码扩展,那为什么又要对修改封闭么?举个例子,比如要给银行的交易功能添加或测试新的功能,如果直接修改源代码,那么造成有些交易发生异常,甚至无法交易。所以,对修改(源码)是封闭的。

装饰器的出现完美的遵循了这个开放封闭原则。

通过上面的统计函数运行时间的例子可以看到,只需在测试的函数上加上统计时间功能的装饰器。而对于原函数没有做任何修改。

装饰器

装饰器的本质:装饰器本身是任意可调用对象,被装饰的对象也可以是任何可调用的对象。

装饰器的功能:在不修改被装饰对象源代码,以及调用方式的前提下,为其添加新的功能。

上面说的有点绕,现在只需记住:

  • 不修改被装饰对象的源代码。

  • 不修改被调用对象的调用方式,就是说,我们在被装饰对象"不知不觉"中添加了一些功能。

装饰器需要达到的目标:添加新功能。

装饰器使用场景:测试功能函数的运行时间,但是不可以修改功能函数的代码。

import time

def timer(func):
    def wrapper():
        start = time.time()
        res = func()
        end = time.time()
        print("程序运行时间:", end - start)

    return wrapper

@timer
def add():
    print("功能函数!")
    time.sleep(2)        # 模拟运行了2秒

add()

#结果为:
功能函数!
程序运行时间: 2.0002386569976807

一个最简单的计算时间的装饰器函数完成了。上面的代码流程是:

  • 第1步:首先在第1行导入time模块。然后程序往下走。
  • 第2步:在第2行定义timer函数。
  • 第3步:接着执行到第9行,发现装饰器的语法糖。这一步你可以想象语法糖默默的帮我们做了定义foo函数,并且执行foo = timer(foo)这一步赋值操作。
  • 第4步:然后触发timer函数执行,执行timer内部代码,程序执行第4行,定义wrapper函数。只是定义,所以程序往下走。
  • 第5步:接着在第8行将wrapper函数名返回。
  • 第6步:timer函数暂时执行完毕,期间做了包括将执行timer函数并为func形参传递实参foo函数名,在嵌套作用域内"记住"foo变量(foo函数名),经过这一些列操作。程序从新回到语法糖的第9行并继续往下走。
  • 第7步:因为在第3步骤时,语法糖帮我们定义了foo函数,此时就直接执行到12行,执行foo加括号。关键点:此时的foo变量已经不是最初的foo函数那个函数名了,而是在第3步骤中拿到的foo变量,而这个foo变量实为timer函数的返回值——wrapper函数名。加括号执行的是wrapper函数。所以,此时程序执行第4行的wrapper函数,接着执行内部代码。
  • 第8步:程序执行到第5行,通过time模块获取到当前的时间戳,程序往下走。
  • 第9步:执行到了第6行,在局部作用域去找变量func,没找到,往上去嵌套作用域里找,这次找到了,在第3步骤中,语法糖给func传递了foo函数名,此时func加括号等价于foo函数加括号执行。
  • 第10步:程序再次通过第9行的语法糖开始执行到第11行的foo函数的内部代码,“睡”1秒,至此,被装饰函数的内部代码执行完毕。程序往下走。
  • 第11步:第6行的func加括号执行完毕,继续执行到了第7行的打印,通过__name__拿到了func的函数名为foo,再一次获取当前的时间戳并减去第5行时获得的时间戳,算出程序运行了多少时间,通过占位符格式化完毕,打印出结果。wrapper函数执行完毕,回到第12行。foo加括号执行完毕,继续往下走,没有代码,程序结束。

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值