本节内容

1、概述

2、装饰器定义

3、装饰器定义

4、带参数的生成器

一、概述

我们之前介绍了大幅片的内容,感觉跟装饰器半毛钱关系都没有,其实不然,我们分别详细阐述了高阶函数和内置函数,下面我们就来讲讲什么是真正的装饰器。

二、装饰器定义

首先装饰器实现的条件:高阶函数+嵌套函数 =》装饰器

1、定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import time
 
#定义内置函数
def timmer(func):  #timmer(test1) func=test1
    def deco():
        start_time = time.time()
        func()   #run test1()
        stop_time = time.time()
        print("the func run time is %s"%(stop_time-start_time))
 
    return deco
 
#装饰test1函数
@timmer  # 相当于test1 = timmer(test1)
def test1():
    time.sleep(3)
    print("in the test1")
 
#直接执行test1函数   
test1()
 
#输出
in the test1
the func run time is 3.0002999305725098

执行步骤:

  1. 执行timmer函数,timmer(test1) 返回值赋值给test1变量,即test1=timmer(test1)
  2. 此时的test1的值是执行timmer函数返回值deco,即test1=deco
  3. 所以执行test1,其实就是执行的是deco函数,test1()其实就是执行deco函数。

2、执行函数带参数

我们先来试试,如果被装饰的函数需要传入参数怎么办?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import time
 
def timmer(func):  #timmer(test1) func=test1
    def deco():
        start_time = time.time()
        func()   #run test1()
        stop_time = time.time()
        print("the func run time is %s"%(stop_time-start_time))
 
    return deco
 
@timmer
def test2(name,age):
    print("name:%s,age:%s"%(name,age))
 
test2()
 
#输出
Traceback (most recent call last):
  File "D:/PycharmProjects/pyhomework/day4/装饰器/装饰器高潮.py", line 23in <module>
    test2()
  File "D:/PycharmProjects/pyhomework/day4/装饰器/装饰器高潮.py", line 8in deco
    func()   #run test1()
TypeError: test2() missing 2 required positional arguments: 'name' and 'age' #缺少传入name和age参数

很显然是错误的,错误的。因为这边执行的test2函数其实就是执行的deco函数,deco函数体内的func()其实就是执行test2函数,但是,test2需要传入name和age两个参数,所以报错。那怎么解决呢?我们只能传入参数了,但是你又不能确定传入几个参数,所以我们只能用非固定参数传参。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import time
 
def timmer(func):  #timmer(test1) func=test1
    def deco(*args,**kwargs):  #传入非固定参数
        start_time = time.time()
        func(*args,**kwargs)   #传入非固定参数
        stop_time = time.time()
        print("the func run time is %s"%(stop_time-start_time))
 
    return deco
 
#不带参数
@timmer  # 相当于test1 = timmer(test1)
def test1():
    time.sleep(3)
    print("in the test1")
 
#带参数
@timmer
def test2(name,age):
    print("name:%s,age:%s"%(name,age))
#调用
test1()
test2("zhangqigao",22)
 
#输出
#test1
in the test1
the func run time is 3.0010883808135986
#test2
name:zhangqigao,age:22
the func run time is 0.0  #test2

三、执行函数有返回值

上面的例子,被调用的函数都没有返回值,那如果,我们被调函数有返回值,该如何做呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def timmer(func):  #timmer(test1) func=test1
    def deco(*args,**kwargs):
        res = func(*args,**kwargs) #这边传入函数结果赋给res
        return res   # 返回res
    return deco
 
@timmer
def test1():  # test1 =  timmer(test1)
    print("in the test1")
    return "from the test1" #执行函数test1有返回值
 
res = test1()
print(res)
 
#输出
in the test1
from the test1

通过上面的例子,可以看出,其实就是在内置函数中把传入参数的执行结果赋给res,然后再返回res变量。

四、带参数的装饰器

之前我们的装饰器都是没有带参数的,其实我们已经能解决90%的问题了,但是如果说有一种情况:就是在你访问不通页面时,你用的验证的方式来源不同,这时你该怎么办?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#本地验证
user,passwd = "zhangqigao","abc123"
 
def auth(auth_type):  #传递装饰器的参数
    print("auth func:",auth_type)
    def outer_wrapper(func):   # 将被装饰的函数作为参数传递进来
        def wrapper(*args,**kwargs):  #将被装饰函数的参数传递进来
            print("wrapper func args:",*args,**kwargs)
            username = input("Username:").strip()
            password = input("Password:").strip()
            if auth_type == "local":
                if user == username and passwd == password:
                    print("\033[32mUser has passed authentication\033[0m")
                    res = func(*args,**kwargs)
                    print("--after authentication")
                    return res
                else:
                    exit("Invalid username or password")
            elif auth_type == "ldap":
                pass
        return wrapper
    return outer_wrapper
 
def index():
    print("welcome to index page")
 
@auth(auth_type="local")  #带参数装饰器
def home():
    print("welcome to home page")
    return "from home"
 
@auth(auth_type="ldap")   #带参数装饰器
def bbs():
    print("welcome  to bbs page")
 
index()
home()
bbs()

重上面的例子可以看出,执行步骤:

  1. outer_wrapper = auth(auth_type="local")
  2. home = outer_wrapper(home)
  3. home()

所以这个函数的作用分别是:

  1. auth(auth_type) 传递装饰器的参数
  2. outer_wrapper(func) 把函数当做实参传递进来
  3. wrapper(*args,**kwargs) 真正执行装饰的函数

函数和常用模块【day05】:装饰器高潮(三)的更多相关文章

  1. 小白的Python之路 day4 装饰器高潮

    首先装饰器实现的条件: 高阶函数+嵌套函数 =>装饰器 1.首先,我们先定义一个高级函数,去装饰test1函数,得不到我们想要的操作方式 import time #定义高阶函数 def deco ...

  2. 探究functools模块wraps装饰器的用途

    <A Byte of Python>17.8节讲decorator的时候,用到了functools模块中的一个装饰器:wraps.因为之前没有接触过这个装饰器,所以特地研究了一下. 何谓“ ...

  3. python进阶04 装饰器、描述器、常用内置装饰器

    python进阶04 装饰器.描述器.常用内置装饰器 一.装饰器 作用:能够给现有的函数增加功能 如何给一个现有的函数增加执行计数的功能 首先用类来添加新功能 def fun(): #首先我们定义一个 ...

  4. 为什么 Python 没有函数重载?如何用装饰器实现函数重载?

    英文:https://arpitbhayani.me/blogs/function-overloading 作者:arprit 译者:豌豆花下猫("Python猫"公众号作者) 声 ...

  5. Python初学者第二十三天 函数进阶(2)装饰器

    装饰器: 需求----> 写一个功能,测试其他同事函数的调用效率. 第一版:功能版 import time def func(): time.sleep(0.2) print('非常复杂') d ...

  6. python函数知识七 闭包、装饰器一(入门)、装饰器二(进阶)

    21.闭包 闭包:在嵌套函数内,使用非全局变量(且不使用本层变量) 闭包的作用:1.保证数据的安全性(纯洁度).2.装饰器使用 .__closure__判断是否是闭包 def func(): a = ...

  7. 函数和常用模块【day05】:装饰器前奏(一)

    本节内容 定义 原则 实现装饰器的储备知识 函数及变量 高阶函数 一.定义 1.装饰器:本质是函数. 2.功能:用来装饰其他函数,顾名思义就是,为其他的函数添加附件功能的. 二.原则 不能修改被装饰函 ...

  8. Day05:装饰器,三元表达式,函数的递归,匿名/内置函数,迭代器,模块,开发目录

    上节课复习:1.函数的对象    函数可以被当作数据取处理2.函数嵌套    嵌套调用:在调用一个函数时,函数体代码又调用了其他函数    嵌套定义:在一个函数内部又定义了另一个函数 def foo( ...

  9. python函数与模块(装饰器,文件处理,迭代器等)

    os模块 os.system('命令') 利用python调用系统命令,命令可以是以列表或者元组内的元素形式* res import os res=os.system('ipconfig') prin ...

随机推荐

  1. 构建之法--初识Git

    该作业来自于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103 GitHub地址:https://github.com/GVic ...

  2. Maven -Maven配置tomcat插件 两种

    Maven Tomcat插件现在主要有两个版本,tomcat-maven-plugin和tomcat7-maven-plugin,使用方式基本相同. tomcat-maven-plugin 插件官网: ...

  3. ajax 异步请求 代码

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  4. Vue 的语法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Sqlite,libevent,openssl,mosquito交叉编译

    一.设置交叉编译环境 在makefile所在目录(或源代码根目录)打开终端. 在终端中设置交叉编译所需的临时环境变量(也可写到配置文件中设置为全局环境变量),其中交叉编译工具链的名称和目录需要根据实际 ...

  6. [转帖]Nginx安装及配置详解 From https://www.cnblogs.com/zhouxinfei/p/7862285.html

    Nginx安装及配置详解   nginx概述 nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:nginx可以作为一个HTTP ...

  7. 解决问题的方法=>现象-->原因-->方案-->方案的优缺点

    解决问题的方法=>现象-->原因-->方案-->方案的优缺点

  8. Spring AOP切点表达式用法总结

    1. 简介        面向对象编程,也称为OOP(即Object Oriented Programming)最大的优点在于能够将业务模块进行封装,从而达到功能复用的目的.通过面向对象编程,不同的模 ...

  9. BZOJ4517[Scoi2016]美味——主席树

    题目描述 一家餐厅有 n 道菜,编号 1...n ,大家对第 i 道菜的评价值为 ai(1≤i≤n).有 m 位顾客,第 i 位顾客的期 望值为 bi,而他的偏好值为 xi .因此,第 i 位顾客认为 ...

  10. day28 classmethod 装饰器

    类方法装饰类方法 把一个方法变成类中的方法 之后调用此方法不需要对类实例化后在调用 直接通过类.方法即可调用 class Goods: __discount = 0.5 def __init__(se ...