• Python函数之—— 装饰器(Day13)


    一.什么是装饰器

    顾名思义,装饰器指为其他函数添加新功能

    装饰器定义:本质就是函数,功能是为其他函数添加新功能

    二.装饰器需要遵循的原则

    1.不修改被装饰函数的源代码(开放封闭原则)

    2.为被装饰函数添加新功能后,不修改被修改函数的调用方式

    3.装饰器的本质 :闭包函数

    功能:就是在不改变原函数调用方式的情况下,在这个函数前后加上扩展功能

    示例1:

    import time
    def timmer(func):
        #函数名可以当做函数的参数
        def inner():
            start = time.time()
            func()
            end = time.time()
            print(end - start)
        return inner
    
    def hahaha():
        time.sleep(0.1)
        print('aaaa')

    示例2:

    def timmer(func):  #---> hahaha
        def inner(x,y):
            func(x,y)  # --->hahaha
        return inner
    
    def hahaha(a,b):
        time.sleep(0.1)
        print(a,b)
    
    def kkk(a):
        print(a)

    三.装饰器的主要功能和装饰器的固定结构

    装饰器的主要功能:

    在不改变函数调用方式的基础上在函数的前、后添加功能。

    装饰器的固定格式:

    def timer(func):
        def inner(*args,**kwargs):
            '''执行函数之前要做的'''
            re = func(*args,**kwargs)
            '''执行函数之后要做的'''
            return re
        return inner

    语法糖

    import time
    def wrapper(func):  # 装饰
        def inner(*args, **kwargs):
            start = time.time()
            ret = func(*args, **kwargs)
            end = time.time()
            print(end - start)
            return ret
        return inner
    
    @wrapper
    def lll():
        time.sleep(0.1)
        print('hello')
    
    lll()

     四.

      1.带参数的装饰器

    def outer(flag):
        def timer(func):
            def inner(*args,**kwargs):
                if flag:
                    print('''执行函数之前要做的''')
                re = func(*args,**kwargs)
                if flag:
                    print('''执行函数之后要做的''')
                return re
            return inner
        return timer
    
    @outer(False)
    def func():
        print(111)
    
    func()
    View Code
    F = False
    def outer(flag):
        def wrapper(func):
            def inner(*args,**kwargs):
                if flag:
                    print('before')
                    ret = func(*args,**kwargs)
                    print('after')
                else:
                    ret = func(*args, **kwargs)
                return ret
            return inner
        return wrapper
    
    @outer(F)  #-->@wrapper  -->hahaha = wrapper(hahaha)  #-->hahaha == inner
    def hahaha():
        print('hahaha')
    
    @outer(F)   #shuangww = outer(shuangww)
    def shuangww():
        print('shuangwaiwai')
    
    shuangww()
    hahaha()
    View Code

    2.多个装饰器装饰同一个函数

    def qqxing(func):  #func = pipixia_inner
        def qqxing_inner(*args,**kwargs):
            print('in qqxing:before')
            ret = func(*args,**kwargs)  #pipixia_inner
            print('in qqxing:after')
            return ret
        return qqxing_inner
    
    def pipixia(func):  #dapangxie
        def pipixia_inner(*args,**kwargs):
            print('in pipixia:before')
            ret = func(*args,**kwargs)      #dapangxie
            print('in pipixia:after')
            return ret
        return pipixia_inner
    
    #qqxing(pipixia_inner)  -->dapangxie = qqxing_inner()
    @qqxing    #dapangxie = qqxing(dapangxie)  -->dapangxie = qqxing(pipixia(dapangxie)) -->
    @pipixia   #dapangxie = pipixia(dapangxie)
    def dapangxie():
        print("饿了么")
    dapangxie()
    View Code

     3.开放封闭原则

    (1)对扩展是开放的

    我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。

    (2)对修改是封闭的

    就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。

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

    练习:

    '''
    编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),
    要求登录成功一次,后续的函数都无需再输入用户名和密码
    注意:从文件中读出字符串形式的字典,
    可以用eval('{"name":"egon","password":"123"}')转成字典格式
    '''
    # user_dict = {
    #     'pang':'123456',
    #     'panda':'binbin',
    #     'nezha':'101010'
    # }
    # print(type(user_dic))
    auth_status = {
        'user':None,          #设置全局的字典
        'status':False
    }
    def auth(func):
        def inner(*args,**kwargs):
            if auth_status['status']:     #如果auth_status为真,直接调用就行
                ret = func(*args, **kwargs)  # index/home
                return ret
            else:
                username = input('username : ').strip()#.strip()避免用户输入带有空格的用户名
                password = input('password : ').strip()
                # 读文件获取用户信息
                f = open('conf')  #文件句柄
                user_info = f.read()  #读取user用户信息
                user_dic = eval(user_info)   #通过eval转换成字典
                if user_dic.get(username) and user_dic[username] == password:#获取字典的k,确认有存在的用户名并找到对应的密码
                    print('login successful')
                    auth_status['user'] = username
                    auth_status['status'] = True
                    ret = func(*args,**kwargs)  #index/home  如果登录成功执行func
                    return ret
                else:
                    print('login failed')
        return inner
    
    @auth   #装饰器
    def index():
        print("欢迎来到首页")
    
    @auth
    def home():
        print("欢迎回家")
    
    index()
    index()
    home()
    index()
    # #认证功能
    # #获取用户名和密码
    # username = input('username : ').strip()
    # password = input('password : ').strip()
    # #读文件获取用户信息
    # f = open('conf')
    # user_info = f.read()
    # user_dic = eval(user_info)
    # if user_dic.get(username) and user_dic[username] == password:
    #     print('login successful')
    # else:
    #     print('login failed')
    '''
    进阶练习:
    1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
    2.编写装饰器,实现缓存网页内容的功能:
    具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),
    就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
    '''
    url_l = []
    from urllib.request import urlopen
    
    def get_cache(func):
        def inner(*args,**kwargs):
            url = args[0]
            filename = str(hash(url))
            if url in url_l:
                f = open(filename,'rb')
                ret = f.read()
            else:
                url_l.append(url)
                ret = func(*args, **kwargs)
                f = open(filename,'wb')
                f.write(ret)
            f.close()
            return ret
        return inner
    
    @get_cache
    def get(url):
        return urlopen(url).read()
    
    print(get('http://www.cnblogs.com/linhaifeng'))
    有一种能力,是持续不断的努力
  • 相关阅读:
    SharePoint服务器端对象模型 之 访问用户、用户组和权限(Part 2)
    SharePoint服务器端对象模型 之 访问用户、用户组和权限(Part 1)
    SharePoint服务器端对象模型 之 使用LINQ进行数据访问操作(Part 4)
    SharePoint服务器端对象模型 之 使用LINQ进行数据访问操作(Part 3)
    SharePoint 服务器端对象模型 之 使用LINQ进行数据访问操作(Part 2)
    Restful.Data 开源持久层组件项目最新进展和使用说明
    高性能网站架构设计之缓存篇(6)- Redis 集群(中)
    让 asp.net 在 mac 上飞
    高性能网站架构设计之缓存篇(5)- Redis 集群(上)
    高性能网站架构设计之缓存篇(4)- Redis 主从复制
  • 原文地址:https://www.cnblogs.com/shaojiafeng/p/7245423.html
Copyright © 2020-2023  润新知