八、函数高级、装饰器

学习目标

  • 能够使用递归函数计算斐波那契额数列
  • 能够定义和使用匿名函数
  • 使用说出匿名函数的使用场景
  • 能够使用高阶函数
  • 能够使用装饰器计算一段代码的执行时长
  • 能够使用装饰器进行权限验证(不强制要求)

一、递归函数

  • 递归简单来说,就是函数内部自己调用自己
def test(a):
    return a + test(a-1) if a > 1 else a == 1
test(10)

二、匿名函数

  • lambda 关键字能创建小型匿名函数。这种函数得名于省略了用def声明函数的标准步骤。lambda函数的语法只包含一个语句,如下:
lambda 参数列表:运算表达式
def add(a,b):
    return a + b
fn = add # 相当于给函数fn起 别名。fn与x均指向同一函数的物理地址空间
print(fn(3,7)) # 等价于add(3,7)

# 除了使用 def 关键字定义一个函数以外,我们还能使用 lambda 表达式定义一个函数
# 用来表达一个简单的函数,函数调用的次数很少,基本上就是调用一次
# 调用匿名函数的两种方式
# 1. 给它定义一个名字(很少这样使用)
mul = lambda a, b: a * b # 匿名函数
print(mul(4,5))

# 2. 把这个函数当做参数传给另一个函数使用(使用场景比较多)
def calc(a,b,fn)
    c = fn(a,b)
    return c

# 回调函数,使用函数作为参数传入,在合适的时间作调用
x1 = calc(1,2,lambda a, b: a + b)

三、列表相关的一些方法

3.1 sort与sorted方法

# 有几个内置函数和内置类,用到了匿名函数
nums = [4,8,2,1,7,6]

# 列表的sort方法,会直接对列表进行排序
nums.sort()

# sorted内置函数,不会改变原有的数据,而是生成一个新的有序的列表
x = sorted(nums)

students = [
    {'name':'zhangsan','age':18,'score':98,'height':180},
    {'name':'lisi','age':21,'score':97,'height':185},
    {'name':'jack','age':22,'score':100,'height':175},
    {'name':'tony','age':23,'score':90,'height':176},
    {'name':'herry','age':20,'score':95,'height':172}
]
# 字典和字典之间不能使用比较运算
# students.sort()

# 需要传递参数 key 指定比较规则
# key 参数类型是函数
# 在 sort 内部实现的时候,调用了 foo 方法,并且传入了一个参数,参数就是列表里的元素(字典)
students.sort(key=foo) 

def foo(ele):
    return ele['age'] # 通过返回值告诉sort方法,按照元素的哪个属性进行排序

# 匿名方法的使用
students.sort(key=lambda ele: ele['age']) 

3.2 filter内置类

# filter 对可迭代对象进行过滤,得到的是一个 filter 对象
# python2的时候是内置函数,python3修改成了一个内置类

# filter 可以给定两个参数,第一个参数是函数, 第二个参数是可迭代对象
# filter结果是一个 filter 类型的对象,filter对象也是一个可迭代对象
ages = [12,23,30,17,16,22,19]
x = filter(lambda ele: ele > 18, ages)
y = list(x) # 转换为list

3.3 map内置类

# 将可迭代对象中每一个元素,均执行一次函数内容并用其返回值进行替换
ages = [12,23,30,17,16,22,19]
m =  map(lambda ele: ele+2,ages) # [14,25,32,19,18,24,21]
print(list(m))

3.4 reduce

# reduce 以前是一个内置函数,现在在functools模块内
# 内置函数和内置类都在 builtins.py文件里
from functools import reduce # 导入模块的语句
scores = [100,89,76,87]
print(reduce(lambda ele1,ele2: ele1+ele2, scores,0))
# reduce是循环操作可迭代对象元素的方法

四、常用内置函数总结

在这里插入图片描述

五、高阶函数

# 1. 一个函数作为另一个函数的参数(如lambda匿名函数的常用使用方式)
# 2. 一个函数作为另一个函数的返回值
def foo():
    print('我是foo,我被调用了')
    return 'foo'

def bar():
    print('我是bar,我被调用了')
    return foo
x = bar() # x指向foo函数
x()

# 3. 函数内部再定义一个函数
def outer():
    m = 100
    def inner():
        n = 90
        print('我是inner函数')
    print('我是outer函数')
    return inner

x = outer() # 我是outer函数 
x() # 我是inner函数 

5.1 函数的嵌套

def outer():
    m = 100
    print('我是outer函数')

    def inner(): # inner函数时定义在outer函数内部的一个函数
        print('我是inner函数')

    if x > 18:
        inner()
    return 'hello'

5.2 闭包的概念

  • 闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数块+引用环境
def outer(n):
    num = n # 外部函数的局部变量num(n也是局部变量)
    def inner():
        # 内部函数声明使用外部函数的局部变量使用 nonlocal
        # nonlocal num
        # num = 10
        return num+1 # 在内嵌函数中引用到外层函数中的局部变量num
    return inner

print(outer(3)()) # 4
'''
当我们调用分别由不同的参数调用 outer 函数得到的函数时,得到的结果是隔离的(相互不影响的),也就是说每次调用outer函数后都将生成并保存一个新的局部变量num,这里outer函数返回的就是闭包。如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)
'''

六、装饰器

6.1 计算一段代码的执行时间

import time # time模块可以获取当前的时间

# 代码运行之前,获取一下时间
start = time.time() # time模块里的time方法,可以获取当前时间的时间戳
# 时间戳是从 1970-01-01 00:00:00 UTC 到现在的秒数
x = 0
for i in range(1,100000):
    x += i
print(x)
# 代码运行完成以后,再获取一个时间
end = time.time()

print('代码运行耗时{}秒'.format(end - start))

6.2 优化计算时间的代码

import time
def cal_time(fn):
    start = time.time()
    fn()
    end = time.time()
    print('代码运行耗时{}秒'.format(end - start))

def demo():
    x = 0
    for i in range(1,100000):
        x += i

cal_time(demo)

6.3 装饰器的使用

import time

def cal_time(fn):
    def inner():
        start = time.time()
        fn()
        end = time.time()    

    return inner

@cal_time # step1:调用cal_time; step 2:把被装饰的函数传递给fn; step 3: 执行函数变量赋值 demo = cal_time(demo),demo指向inner函数
def demo():
    x = 0
    for i in range(1,100000):
        x += i
    print(x)

# step 3:当再次调用demo函数时,这时的demo函数已经不是上面的demo了,而是inner函数
# demo() # 实质inner()
# 不同的被装饰器装饰的方法对应的不同存储地址的inner方法
demo()

6.4 装饰器详解

  • 以下情况见链接:

https://www.runoob.com/w3cnote/python-func-decorators.html ---- python函数装饰器

  1. @wrap(fn)的使用
  2. 带参数的装饰器写法 @outer(param)

def cal_time(fn):
    def inner(x,*args,**kwargs): # 设置包含被装饰方法参数的参数列表
        start = time.time()
        s = fn(x)
        end = time.time()    
        return s # 返回装饰器装饰方法的返回值

    return inner

@cal_time
def demo(n):
    x = n
    for i in range(1,100000):
        x += i
    print(x)

# demo实际指向inner函数块,实参列表由inner函数限制
demo(100000,'hello',y=1)
# 带参数的装饰器
def can_play(clock):
    def handle_action(fn):
        def do_action(*args,**kwargs):
            if clock < 21:
                fn(name,game)
            else:
                print('太晚了,不能玩儿游戏了')
        return do_action
    return handle_action

@can_play(22) # 装饰器函数带参数
def play_game(name, game):
    print(name + '正在玩儿' + game)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ModelBulider

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值