装饰器

1.1 开放封闭原则

开放封闭原则具体定义是这样:

1.对扩展是开放的

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

2.对修改是封闭的

因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对函数内部进行修改,或者修改了函数的调用方式,很有可能影响其他已经在使用该函数的用户。

定义:在不改变原被装饰的函数的源代码以及调用方式下,为其添加额外的功能。

实现真正的开放封闭原则:装饰器。

运用闭包原理:

import time
def index():
    time.sleep(2)  # 模拟一下网络延迟以及代码的效率
    print('这是一个主页')

def access_index(name):
    time.sleep(3)  # 模拟一下网络延迟以及代码的效率
    print(f'欢迎访问{name}主页')

套一层最外面的函数timer,然后将里面的inner函数名作为最外面的函数的返回值

def timer(func):  # func = index
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f'此函数的执行效率为{end_time-start_time}')
    return inner
# f = timer(index)
# f()

我们分析一下代码,代码执行到这一行:f = timer(index) 先执行谁?看见一个等号先要执行等号右边, timer(index) 执行timer函数将index函数名传给了func形参。内层函数inner执行么?不执行,inner函数返回 给f变量。所以我们执行f() 就相当于执行inner闭包函数。 f(),这样既测试效率又执行了原函数,有没有问题?当然有啦!!我们要解决原函数执行方式不改变的问题,怎么做? 所以你可以把 f 换成 index变量就完美了! index = timer(index) 特别要注意 函数外面的index实际是inner函数的内存地址而不是index函数。这个timer就是最简单版本装饰器,在不改变原index函数的源码以及调用方式前提下,为其增加了额外的功能,测试执行效率。

1.2标准版装饰器

def wrapper(func):
    def inner(*args,**kwargs):
        '''执行被装饰函数之前的操作'''
        ret = func(*args,**kwargs)
        '''执行被装饰函数之后的操作'''
        return ret
    return inner
import time
def wrapper(f):
    def inner(*args,**kwargs):
        start = time.time()     #调用函数之前的操作
        f(*args,**kwargs)
        end = time.time()
        print(end - start)  #调用函数之后的操作
    return inner

def func(*args,**kwargs):
    time.sleep(0.5)
    print(f"{args[0]}暴打{args[1]}页面!")

func = wrapper(func)
func("章超印","煞笔周道镕")

语法糖:@xxx

import time
def wrapper(f):
    def inner(*args,**kwargs):
        start = time.time()     #调用函数之前的操作
        f(*args,**kwargs)
        end = time.time()
        print(end - start)  #调用函数之后的操作
    return inner

@wapper     # 等于 func = wapper(func)
def func(*args,**kwargs):
    time.sleep(0.5)
    print(f"{args[0]}暴打{args[1]}页面!")

# func = wapper(func)
func("章超印","煞笔周道镕")

带参数的装饰器:

在装饰器的基础上再套一层

你现在要完成的就是你的装饰器要分情况去判断账号和密码,不同的函数用的账号和密码来源不同。 但是你之前写的装饰器只能接受一个参数就是函数名,所以你写一个可以接受参数的装饰器。

dic = {
    "flag":False,
    "username":None

}
msg ="""
QQ
微信
抖音
邮箱
>>>
"""
choose = input(msg).upper()
def auth(argv):
    def wrapper(func):
        def inner(*args, **kwargs):
            if dic["flag"]:
                foo(*args, **kwargs)
            else:
                if argv == "QQ":
                    print("欢迎来到QQ!")
                    user = input("username:")
                    pwd = input("password:")
                    if user == "zcy1" and pwd == "123":
                        dic["flag"] = True
                        dic["username"] = user
                elif argv == "微信":
                    print("欢迎来到微信!")
                    user = input("username:")
                    pwd = input("password:")
                    if user == "zcy2" and pwd == "1234":
                        dic["flag"] = True
                        dic["username"] = user
                elif argv == "抖音":
                    print("欢迎来到抖音!")
                    user = input("username:")
                    pwd = input("password:")
                    if user == "zcy3" and pwd == "12345":
                        dic["flag"] = True
                        dic["username"] = user
                else:
                    print("欢迎来到邮箱!")
                    user = input("username:")
                    pwd = input("password:")
                    if user == "zcy4" and pwd == "123456":
                        dic["flag"] = True
                        dic["username"] = user
            ret = func(*args, **kwargs)
            return ret
        return inner
    return wrapper

@auth(choose)
# wrapper = auth(choose)
# foo = wrapper()
def foo():
    return "我不管,章超印超帅!"

# @auth(choose)  等于下面的两行
# wrapper = auth(choose)
# foo = wrapper()
print(foo())

@auth('choose') :分两步:

第一步先执行auth('choose')函数,得到返回值wrapper

第二步@与wrapper结合,形成装饰器@wrapper然后在依次执行。

这样就是带参数的装饰器,参数可以传入多个

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

被装饰的函数正上方有多个装饰器,先执行离被装饰函数最近的装饰器

我们现在知道标准装饰器和带参数的装饰器,我们来看看多个装饰器装饰一个函数:

def wrapper1(func):
    def inner1(*args,**kwargs):
        print("这是装饰器一开始")
        func(*args,**kwargs)
        print("这是装饰器一结束")
    return inner1

def wrapper2(func):
    def inner2(*args,**kwargs):
        print("这是装饰器二开始")
        func(*args,**kwargs)
        print("这是装饰器二结束")
    return inner2

@wrapper1
@wrapper2
def func():
    print("这是被装饰的函数")

func()

大家来推断一下,这个的打印结果

这是装饰器一开始
这是装饰器二开始
这是被装饰的函数
这是装饰器二结束
这是装饰器一结束
 先执行离被装饰的函数最近的语法糖
# 小技巧:进入装饰器从上往下,走到最会一个装饰器执行被装饰的函数,退出装饰器从下往上走

百万年薪python之路 -- 装饰器的更多相关文章

  1. 百万年薪python之路 -- 装饰器进阶

    本文链接:https://blog.csdn.net/xiemanR/article/details/72510885 一:函数装饰函数 def wrapFun(func): def inner(a, ...

  2. python之路--装饰器

    二 .通用装饰器的写法 python里面的动态代理. 存在的意义: 在不破坏原有的函数和原有函数的调用基础上,给函数添加新的功能 def wrapper(fn): # fn是目标函数. def inn ...

  3. python之路——装饰器函数

    阅读目录 楔子 装饰器的形成过程 开放封闭原则 谈装饰器主要功能和装饰器固定结构 带参数的装饰器 多个装饰器装饰一个函数 返回顶部 楔子 作为一个会写函数的python开发,我们从今天开始要去公司上班 ...

  4. 百万年薪python之路 -- 面向对象之所有属性及方法

    1.私有成员公有成员 1.1 类的私有属性 # class A: # # name = '周道镕' # __name = 'zdr' # 私有类的属性 # # def func(self): # pr ...

  5. 百万年薪python之路 -- 软件的开发规范

    一. 软件的开发规范 什么是开发规范?为什么要有开发规范呢? 你现在包括之前写的一些程序,所谓的'项目',都是在一个py文件下完成的,代码量撑死也就几百行,你认为没问题,挺好.但是真正的后端开发的项目 ...

  6. python之路---装饰器函数

    阅读目录 楔子 装饰器的形成过程 开放封闭原则 谈装饰器主要功能和装饰器固定结构 带参数的装饰器 多个装饰器装饰一个函数 返回顶部 楔子 作为一个会写函数的python开发,我们从今天开始要去公司上班 ...

  7. 百万年薪python之路 -- 闭包

    2.闭包 闭包的定义: 闭包是嵌套在函数中的函数. 闭包必须是内层函数对外层函数的变量(非全局变量)的引用. 一句话定义就是:在嵌套函数内,对非全局变量 (且不是本层的变量)的引用 如何判断判断闭包? ...

  8. 百万年薪python之路 -- 前端CSS样式

    CSS样式 控制高度和宽度 width宽度 height高度 块级标签能设置高度和宽度,而内联标签不能设置高度和宽度,内联标签的高度宽度由标签内部的内容来决定. 示例: <!DOCTYPE ht ...

  9. 百万年薪python之路 -- 面向对象之 反射,双下方法

    面向对象之 反射,双下方法 1. 反射 计算机科学领域主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省) python面向对象中的反射:通过字符串的形式操作对象相关的属性.python ...

随机推荐

  1. [C++] 重载new和delete——控制内存分配

      1.new和delete表达式的工作机理      1)new表达式实际执行了三步 string *sp=new string("aaaa"); ];//string采用默认初 ...

  2. vscode Springboot 启动debug报错:Build failed, do you want to continue?

    一,前言 vscode我感觉是一个特别好用的开发工具,我根据文章https://www.cnblogs.com/WangBoBlog/p/9464281.html去搭建一个简单的springboot工 ...

  3. 记一个复杂组件(Filter)的从设计到开发

    此文前端框架使用 rax,全篇代码暂未开源(待开源) 原文链接地址:Nealyang/PersonalBlog 前言 貌似在面试中,你如果设计一个 react/vue 组件,貌似已经是司空见惯的问题了 ...

  4. Python + opencv 实现图片文字的分割

    实现步骤: 1.通过水平投影对图形进行水平分割,获取每一行的图像: 2.通过垂直投影对分割的每一行图像进行垂直分割,最终确定每一个字符的坐标位置,分割出每一个字符: 先简单介绍一下投影法:分别在水平和 ...

  5. Win系统下使用命令链接MySQL数据库

    方法一: 1:打开[开始]>[运行]输入[cmd]单击[确定]后出现CMD命令黑色窗口,这就是我们说的CMD命令行 2:默认进入C盘,于是我们可以进入E盘,点击回车.因为我的数据库是存放在E盘的 ...

  6. Angular 样式绑定

    1. style.propertyName [style.Css属性名] = 'Css属性值变量'/"'css属性值'" // app.component.ts export cl ...

  7. 学习VBA

    学习VBA VBA 就是 (Visual basic for Application) 用的比较多的是在Excel中处理数据,可以方便快捷地使用编程方式来对数据进行操作. VBA 数据类型 Integ ...

  8. 正则表达式在Java中使用

    正则表达式 定义 用一组特殊的字符来描述一组字符串的格式 用于验证字符串是否满足格式 不关心字符串的内容是否有效 1. 基本正则表达式所谓正则表达式就是使用一系列预定义的特殊字符来描述一个字符串的格式 ...

  9. Network in Network(2013),1x1卷积与Global Average Pooling

    目录 写在前面 mlpconv layer实现 Global Average Pooling 网络结构 参考 博客:blog.shinelee.me | 博客园 | CSDN 写在前面 <Net ...

  10. 设计一个A表数据抽取到B表的抽取过程

    原题如下: 解题代码如下: table1类: @Data @NoArgsConstructor @AllArgsConstructor public class table1{ private Str ...