zoukankan      html  css  js  c++  java
  • day047函数之装饰器(闭包的运用),面向对象之单例模式(设计模式)

    本节内容:

    1、函数之装饰器
    2、面向对象之单例模式
    

    一、函数之装饰器(闭包的运用)

    装饰器本质上就是一个python函数,一个闭包函数的运用,
    他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。
    
    装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。
    

    1、装饰器的形成过程

    现在有一个需求,要测试一个函数的执行时间,在不改变这个函数的执行情况下:
    

    fe1:简单版的装饰器

    简单版的装饰器

    # 增加一个函数 测试其他函数执行效率的功能,但是尽量不要改变原函数的执行方式.
    
    import time
    
    def func():  # 被装饰的函数
        time.sleep(0.2)
        print('10万行代码')
    
    def func1():
        time.sleep(0.2)
        print('11万行代码')
    # func = 666
    # func()
    
    def timmer(f):  # func函数名 = f
        def inner():
            start_time = time.time()
            f()
            end_time = time.time()
            print('此函数的执行效率为%s' % (end_time - start_time))
        return inner
    
    func = timmer(func)  # inner
    func()  # inner()
    func1 = timmer(func1)
    func1()
    
    # 上个版本不行,每次执行被测试时间的函数时,必须要加一行代码.
    # 怎么解决,看下面的语法糖
    
    Python

    fe2:装饰器—-语法糖

     装饰器:在不改变原函数的执行(代码机构基础上,给原函数增加一些额外的功能,登录验证,打印日志,测试效率等等.
     语法糖,就是python里面封装好的func = timmer(func),你直接调用就行,不用再自己写了
    

    装饰器的语法糖运用

    import time
    def timmer(f):  # func函数名 = f
        def inner(x,y):
            start_time = time.time()
            f(x,y)
            end_time = time.time()
            print('此函数的执行效率为%s' % (end_time - start_time))
    
        return inner
    
    @timmer #  func = timmer(func)
    def func(x,y):
        time.sleep(0.2)
        print(x + y)
    
    # 语法糖  @
    # @timmer  # func1 = timmer(func1)
    # def func1():
    #     print(666)
    func(10,20)  # inner(10,20)
    # func1()
    
    Python

    fe3:被装饰函数带参数,这时用无敌传参(*args, **kwargs)

    无敌传参解决被装饰函数带参数

    import time
    def timmer(f):  # func函数名 = f
        def inner(*args, **kwargs):  # 传参,聚合
            # args = (10,20)
            start_time = time.time()
            f(*args,**kwargs)  # 被装饰函数的执行  * 打散 10 , 20  f(10,20)
            end_time = time.time()
            print('此函数的执行效率为%s' % (end_time - start_time))
        return inner
    
    @timmer #  func = timmer(func)  func2 = timmer(func2) 这时的func2已经不是被装饰函数了
    def func(x,y):
        time.sleep(0.2)
        print(x + y)
    
    @timmer
    def func2(x,y,z,w):
        print(x,y,z,w)
    # func(10, 20)  # inner(10,20)
    
    func2(1,2,3,w=4)  # 这里的参数被inner的f接收了,f就是语法糖传参的被装饰函数名
    
    Python

    fe4: 标准的装饰器, 被装饰的函数带参数,带返回值

    标准的装饰器

    import time
    def timmer(f):  # func函数名 = f
        def inner(*args, **kwargs):   # 接收被装饰函数的参数
            start_time = time.time()
            ret = f(*args,**kwargs)  # 接收被装饰函数执行之后的返回值
            end_time = time.time()
            print('此函数的执行效率为%s' % (end_time - start_time))
            return ret  # 将返回值,返回给调用者
        return inner
    
    @timmer #  func = timmer(func)
    def func(x,y,z,e):
        time.sleep(0.2)
        return x + y + z + e
    ret1 = func(10, 30, 3, 4)  # inner(10, 30)
    print(ret1)
    
    Python

    2、面试题(手写一个装饰器)

    def wrapper(f):
        def inner(*args, **kwargs):
            '''被装饰函数执行之前的操作'''
            ret = f(*args, **kwargs)
            """被装饰函数执行之后的操作"""
            return ret
        return inner
    
    Python

    3、装饰器的应用: 登录验证.

    需求:登陆后可以在各个页面切换
    

    名字

    dic_status = {
        'username': None,
        'status': False,
    }
    
    def login(f):
        def inner(*args, **kwargs):
            '''被装饰函数执行之前的操作'''
            if dic_status['status'] :
                ret = f(*args, **kwargs)
                return ret
            else:
                username = input('请输入用户名').strip()
                password = input('请输入密码').strip()
                with open('register', encoding='utf-8') as f1:
                    for line in f1:
                        user, pwd = line.split('|')
                        if username == user.strip() and password == pwd.strip():
                            dic_status['username'] = username
                            dic_status['status'] = True
                            print('登录成功,正在跳转...')
                            ret = f(*args, **kwargs)
                            return ret
                    else:
                        print('登录失败...')
        return inner
    
    
    @login
    def article():
        print('欢迎登录文章页面')
    @login
    def diary():
        print('欢迎登录日记页面')
    @login
    def comment():
        print('欢迎登录评论页面')
    
    dic = {
        1: article,
        2: diary,
        3: comment,
    }
    
    while 1:
        num = input('欢迎访问博客园,请选择:
    1文章页面 
    2 日记页面 
     3 评论页面').strip()
        if num.isdigit():
            dic[int(num)]()
        else:
            print('重新输入..')
    # 还需写一个register的文件来放用户信息,进行登录验证
    
    Python

    4、带参数的装饰器

    带参数的装饰器

    import time
    def timmer(flag):  # 这个函数的作用是,将参数传给装饰器函数
        def wrapper(f):  # 这个函数的作用是:将被装饰函数作为参数传入
            def inner(*args, **kwargs):  # 传入被装饰函数的参数,传参
                if flag:  # 通过这个状态来,控制是否执行装饰器函数
                    start_time = time.time()
                    ret = f(*args, **kwargs)
                    end_time = time.time()
                    print('执行时间%s' % (end_time-start_time))
                    return ret
                else:
                    ret = f(*args, **kwargs)
                    return ret
            return inner
        return wrapper
    
    flag1 = False
    @timmer(flag1)  # 第一步,将@ 与后面 分开,只是单纯的执行timmer(flag1)函数 第二部 将@ 与 wrapper相结合,形成装饰器
    def func1():
        time.sleep(0.3)
        print('in func1')
    func1()
    
    Python

    5、多个装饰器 装饰一个函数

    多个装饰器 装饰一个函数

    def wrapper1(func):  # func == f 函数名
        def inner1():
            print('wrapper1 ,before func')  # 2
            func()
            print('wrapper1 ,after func')  # 4
        return inner1
    
    def wrapper2(func):  # func == inner1
        def inner2():
            print('wrapper2 ,before func')  # 1
            func()
            print('wrapper2 ,after func')  # 5
        return inner2
    
    # 就近原则   先将近的传给装饰器函数,多个装饰器的话,逐层上传
    @wrapper2  # f = wrapper2(f) 里面f == inner1  外面的f == inner2
    @wrapper1  # f = wrapper1(f) 里面的f == 函数名f   外面的f == inner1
    def f():
        print('in f')  # 3
    f()  # inner2()
    
    Python

    二、面向对象之单例模式

    就是只能实例化一个对象,不管创建多少个对象,都是指向同一个内存地址
    
    例如:多个py文件在引入同一个模块,如果没有设置
    

    1、单例模式代码示例

    class A:
        __instance = None   # 定义一个私有变量,
        def __new__(cls, *args, **kwargs):  # 通过重写父类的__new__方法,来控制指向第一个实例化对象的地址
            if A.__instance is None:     # 通过私有变量来控制指向第一个实例化对象的(同一个)的地址
                obj = object.__new__(cls)  # 如果是第一次实例化对象,就创建对象,
                A.__instance = obj
            return A.__instance   # 如果不是第一次,就直接指向第一次对象的内存地址,不再创建对象
    
    obj1 = A()
    obj2 = A()
    obj3 = A()
    obj4 = A()
    print(obj1)  # 都指向同一个内存地址
    print(obj2)
    print(obj3)
    print(obj4)
  • 相关阅读:
    新零售解决方案体系架构
    设计模式-分类
    设计模式-设计原则
    一天一个 Linux 命令(12):tree 命令
    RabbitMQ中如何保证消息的可靠传输?如果消息丢了怎么办
    为什么使用MQ?
    一天一个 Linux 命令(11):cp命令
    数据结构和算法-线性查找-二分查找
    作图工具汇总
    Git 命令大全,Git命令汇总,Git命令说明
  • 原文地址:https://www.cnblogs.com/yipianshuying/p/10153645.html
Copyright © 2011-2022 走看看