zoukankan      html  css  js  c++  java
  • fpython-笔记(五)装饰器、匿名函数

    一、装饰器

    装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里面每个函数都加一个功能,用来统计每个函数的运行时间是多少,找出来运行比较慢的函数,来优化代码,或者一个功能在调用之前必须登陆,就需要添加一个新的功能,来统计程序的运行时间,那这样的话,就得修改每个函数了,需要改代码,但是代码特别多,改完了公司倒闭了,这时候装饰器就能排上用场了,它可以不改变原有的函数,原来的函数和原来一模一样,什么都不需要改变,只需要在函数外部加上调用哪个装饰器就可以了。so,装饰器的作用就是不改变原来函数的调用方式,不改变原来函数的代码,给它增加了一个新功能。但是不改变函数,给它增加新功能,那是不可能的,装饰器只不过是偷偷改变了原来的函数而已,而原来的函数不知不觉。

    说白了就是函数嵌套+高阶函数
    作用:就是在不改变原有函数的调用方式,入参的情况下给函数添加新功能
    偷偷摸摸的给函数加上新功能,但是不改变原来的函数

    使用装饰器需要了解的知识:

    *1 函数即变量,意思是在python中函数可以当一个变量来用,函数名就是一个变量,这个变量存的实际上是这个函数的内存地址,在调用的时候从函数名里面这个内存地址找到这个函数。()代表调用函数,如果只打印函数名的话实际上就是打印了一下内存地址。

    def test():
    print('nihao')
    print(test) # 打印函数的内存地址
    test() # 调用函数`

    <function test at 0x0000000002383E18>

    *2 高阶和嵌套函数
    之前的章节提过,实际上装饰器就是高阶函数和嵌套函数的结合体
    下面我们写一个简单的装饰器,用来计算函数的运行时间。

    import time
    def bar():
    time.sleep(3)
    print('测试执行时间')

    def test_time(func)
    start_time = time.time()
    func()
    stop_time = time.time
    print('函数的运行时间是%s'%(stop_time - start_time))
    test_time(bar)

    运行结果:

    测试执行时间
    函数的运行时间是3.000171661376953
    但是这样的话,我们每次要调用test_time(bar),而不是直接调用bar(),所以就改变了函数的调用方式。
    这时我们就想到了装饰器。如果不修改调用代码,也就是意味着调用bar(),需要和test_time(bar)一样的
    效果,如果test_time(bar)并咩有直接产生调用函数的效果,而是返回一个函数的内存地址,那么将
    test1(bar)的返回值赋值给bar,然后,调用bar()的代码完全不用修改!

    import time

    def test_time(func):
    def deco():
    start_time = time.time()
    func()
    stop_time = time.time()
    print('函数的运行时间是%s'%(stop_time - start_time))
    return deco
    def bar():
    time.sleep(3)

    bar = test_time(bar) #把deco的内存地址返回给 bar
    bar()

    运行结果:

    in the bar
    函数的运行时间是3.000171661376953

    函数test_time 其实就是一个装饰器,它把真正的业务方法func包裹在函数里面,看起来就像是bar被test_time装饰了
    如果我们想偷懒不适用赋值语句bar = test_time(bar) ,那么我们就可以用到装饰器的语法糖@,语法糖的意思就是一种语法的简写
    ,他可以使代码看起来更加简洁,上面的bar = test_time(bar) 和@test_time 然后调用bar()效果是一样的。

    import time

    def test_time(func):
    def deco():
    start_time = time.time()
    func()
    stop_time = time.time()
    print('函数的运行时间是%s'%(stop_time - start_time))
    return deco
    @test_time
    def bar():
    time.sleep(3)
    print('in the bar')

    运行的结果和上面一样

    这样我们就提高了程序的可重复利用性,当其他函数需要调用装饰器时,可以直接调用。装饰器在python使用非常方便,这得益于python的函数
    能够像朋友同的对象一样作为参数传递给其他函数,可以赋值给其他变量,可以作为返回值,被定义在另一个函数内。

    如果装饰的函数带有参数,因为你也不知道被装饰的函数会传什么参数,所以可以使用可变参数和关键字参数来接收所有的参数,代码如下:

    def test_time(func):
    def deco(args,**kwargs):
    start_time = time.time()
    func(
    args,**kwargs)
    stop_time = time.time()
    print('函数的运行时间%s'%(stop_time - start_time))
    return deco
    @test_time
    def test2(name,age):
    time.sleep(2)
    print('in the test2',name,age)
    test2('niuhanyang',18)

    运行结果:
    in the test2: niuniu 18
    the func run time is 2.0001144409179688

    下面再用装饰器写一个实例,判断用户是否登录,判断的逻辑是这样,运行程序,打印菜单,如果是选择后台管理和添加商品,
    就判断用户是否登录,如果没有登陆的话,让用户登陆,如果是查看商品就不需要登陆。

    import time,json
    def read_file(filename):
    with open(filename) as fr:
    res = json.load(fr)
    return res

    login_name = None

    def auth(func):
    dec(args,**kwargs):
    global login_name
    if login_name:
    res = func(
    args,kwargs)
    return res
    else:
    user_dic = read_file('users.json')
    count = 0
    while count ❤️:
    username = input('请输入用户名:').strip()
    password = input('请输入密码:').strip()
    if username !='' and password ! ='':
    if username in user_dic:
    if user_dic[username]['password'] = passsword
    login_name =username
    res = func(*args,
    kwargs)
    return res
    else:
    print('密码不正确!!!')
    count +=1
    else:
    print('用户名不存在!!!')
    count +=1
    else:
    print('用户名和密码都不能为空')
    cout+ =1
    return dec

    下面是事先写好的uses.json

    {
    "admin": {
    "password": "123456",
    "cart": [
    "mac",
    "iphone"
    ]
    },
    "duguanglong": {
    "password": "123456",
    "cart": []
    }
    }

    匿名函数

    如果这个函数只需要执行一次,那就定义一个匿名函数,匿名函数只能处理比较简单的处理逻辑,只能写简单的表达式,不能写循环判断,比如三元运算符。
    匿名函数使用lambda关键字,比如说要定义一个函数,它的功能是要返回两个数字相加,那就可以使用lambda,代码如下:

    s = lambda x,y:x+y #冒号前面的x,y是入参,冒号后面的是返回值
    print(s(1,9)) #因为函数即变量,如果没有顶一个变量把lambda存起来的话,他就不在内存里,就没有办法执行,所以把它放到s这个变量里面
    s(1,9)

    运行结果:10

  • 相关阅读:
    编译nginx时openssl报错的解决方案
    编译nginx时make报错[-Werror=implicit-fallthrough=]的解决方案
    centos8下编译安装tomcat
    解决centos安装不上apache:No match for argument: httpd
    编译安装apache
    编译apache出现gcc: error: /usr/lib/rpm/redhat/redhat-hardened-ld: No such file or directory
    配置与管理FTP服务器
    2018icpc南京现场赛-I Magic Potion(最大流)
    Codeforces 1062B Math(质因数分解)
    BZOJ 1009 [HNOI2008]GT考试(矩阵快速幂优化DP+KMP)
  • 原文地址:https://www.cnblogs.com/lingxia/p/7494998.html
Copyright © 2011-2022 走看看