装饰器

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. python 切片步长

    python切片 切片:list变量[值下标:结束值下标]  什么意思呢? 就是获取 list中 下标从定义的位置开始获取数据到  自定义的下标位置结束, 但是切片有个规矩就是顾头不顾尾, 举个例子 ...

  2. JDK 13 都已经发布了,Java 8 依然是最爱

    在 JDK 版本的世界里,从来都是 Oracle 发他的新版本,我们继续用我们的老版本.三年之前用 JDK 7,后来终于升级到了 JDK 8.自从升级了没多久,JDK 就开始了半年发一个新版本的节奏, ...

  3. Maven 创建项目之简单示例

    maven 是一个项目管理工具.可以用来管理jar包依赖,构建项目等. 那么接下来,就在eclipse中使用maven创建一个简单的项目. 1,依次点击File-> New -> Othe ...

  4. 建议收藏 - 专业的MySQL开发规范

    为了项目的稳定,代码的高效,管理的便捷,在开发团队内部会制定各种各样的规范 这里分享一份我们定义的MySQL开发规范,欢迎交流拍砖 数据库对象命名规范 数据库对象 命名规范的对象是指数据库SCHEMA ...

  5. java数据结构——队列、循环队列(Queue)

    每天进步一点点,坚持就是成功. 1.队列 /** * 人无完人,如有bug,还请斧正 * 继续学习Java数据结构————队列(列队) * 队列和栈一样,都是使用数组,但是队列多了一个队头,队头访问数 ...

  6. 部署Tomcat 环境

    部署Tomcat 环境(mysql+tomcat+jdk) 1.下载Tomcat 软件包 2.通过xftp创建root 连接,然后将Tomcat 软件包拖拽到/opt目录下 3.在xshell 上ro ...

  7. 【爬虫小程序:爬取斗鱼所有房间信息】Xpath(线程池版)

    # 本程序亲测有效,用于理解爬虫相关的基础知识,不足之处希望大家批评指正 from queue import Queue import requests from lxml import etree ...

  8. MySQL数据库从复制及企业配置实践

    在实际生产中,数据的重要性不言而喻: 如果我们的数据库只有一台服务器,那么很容易产生单点故障的问题,比如这台服务器访问压力过大而没有响应或者奔溃,那么服务就不可用了,再比如这台服务器的硬盘坏了,那么整 ...

  9. linux分析工具之vmstat详解

    一.概述 vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况.首先我们查看下帮助.如下图所 ...

  10. Scala Eclipse org.eclipse.e4.workbench异常奔溃修复

     Scala Eclipse org.eclipse.e4.workbench异常奔溃修复: 找到<workspace>/.metadata/.plugins/org.eclipse.e4 ...