装饰器1、无参数的装饰器 2、有参数的装饰器 3、装饰器本身带参数的以及如果函数带return结果的情况
装饰器分成三种:
1、无参数的;
2、有参数的;
3、装饰器本身带参数的。
装饰器decorator又叫语法糖
定义:本质是函数,器就是函数的意思。装饰其他函数。就是为其他函数添加附加功能。
原则: 1、不能修改被装饰的函数的源代码;
2、不能修改被装饰的函数的调用方式;
3、装饰器对被装饰的函数是完全透明,就是被装饰的函数,根本不知道装饰器的存在。
实现装饰器知识储备:
1、函数即“变量”
2、高阶函数
3、嵌套函数
高阶函数+嵌套函数=》装饰器的效果
1、函数即变量的意义:
函数跟变量一样,都是内存放着函数体,而有一个函数名指着这个内存的函数体。
计算机的变量x,y就是一个门牌号,他们都指向数值1,对于计算机的内存回收机制,只要数值1,有任意一个变量指向它,那么这个数值1在内存里就不会被清空回收;
函数跟变量一样,函数的内存回收机制跟变量是一模一样的。只要存在函数名,那么函数体存在与内存里,就不会被清空回收;
但是匿名函数,是没有函数名的,那么匿名函数,在内存里就会立马被清空回收。

再来看一个实际的例子,下图中bar()函数,函数体是pass,如果你在命令行里直接打函数名bar(就是门牌号),那么返回的是函数体的内存地址。给函数名bar加两个括号(),那么就是到内存去取函数体,那么bar()返回的就是函数体pass

第1段, 报错的代码:


第2段代码是正确的:


第3段代码,把bar的顺序对调了下:


第4段错误的代码:调用foo函数的时候,bar变量还没定义呢,肯定出错

2、高阶函数的定义:
- 把一个函数名当作实参传给另外一个函数(在不修改被装饰函数源代码的清下为其添加功能);
- 返回值中包含函数名。(不修改函数的调用方式)
首先我们来说说把一个函数名当作实参传给另外一个函数的例子:
下面的这个例子,test1(bar) ,bar这个时候就是门牌号,也就是函数体的内存地址,把内存地址当作实参传给了test1这个函数,同时相当于func=bar,相当于把bar的函数体内存地址赋值给了func。
所以func也就是bar的门牌号,func()取的是bar的函数体!


我们现在升级下上面的这个高阶函数,来做下统计bar这个函数,运行需要多少时间。
模块time:
time.sleep(3)等待3秒
time.time()获取当前时间
时间可以直接相减,获得间隔的秒数



这里的test1就有点类似装饰器了,它的作用就是统计bar函数运行的时间。
这边有一个知识点,高阶函数需要把函数名当作实参传给另外一个函数,所以在上图中,test1(bar)这个写法是正确的,这个时候是把函数的内存地址传给另外一个函数,
但是test1(bar())这个写法就不是高阶函数了,这个是把bar()这个函数的结果传给另外一个函数。这个写法不能说是错误的,但是就不是高阶函数了。
其次我们来说说返回值要求包含函数名的例子:


3、嵌套函数的定义:
下面的这种方式是不行了,不可以调用局部变量:

函数的嵌套,就是在一个函数体里,又申明一次函数。请注意这里说的是申明,而不是调用。

我们再来看一个嵌套函数的例子:这个例子的结果是3

无参数的装饰器
做了这么多的铺垫,我们现在最终来写一个装饰器:



最后,这个写法太麻烦
python3做了个定义:你想给哪个函数加装饰器,就在哪个函数前面@装饰器
@装饰器就表示函数1=装饰器(函数1)

1、最终无参数的装饰器的代码:注意下各个函数什么时候加(),什么时候不加(),很重要的理解!!!


2、有参数的装饰器:(但是注意要兼容无参数的情况,不能说兼容了参数,就把没参数的不兼容了)




3、装饰器本身带参数的情况,以及如果函数带return结果的情况,比如下面的home()就带了return "from home"的结果。需要在装饰器里加return
其实上面两种情况已经可以满足你90%的装饰器的情况了。
我们模拟网站,一个页面就是一个函数,其中有几个页面,需要登录以后才可以浏览访问。登录这个操作用装饰器来完成。
首页index(),用户的页面home()需要本地验证登录,bbs()需要远程验证登录




user,passwd = 'alex','abc123'
def auth(auth_type):
print("auth func:",auth_type)
def outer_wrapper(func):
def wrapper(*args, **kwargs):
print("wrapper func args:", *args, **kwargs)
if auth_type == "local":
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
print("\033[32;1mUser has passed authentication\033[0m")
res = func(*args, **kwargs) # from home
print("---after authenticaion ")
return res
else:
exit("\033[31;1mInvalid username or password\033[0m")
elif auth_type == "ldap":
print("搞毛线ldap,不会。。。。") return wrapper
return outer_wrapper def index():
print("welcome to index page")
@auth(auth_type="local") # home = wrapper()
def home():
print("welcome to home page")
return "from home" @auth(auth_type="ldap")
def bbs():
print("welcome to bbs page") index()
print(home()) #wrapper()
bbs()
装饰器1、无参数的装饰器 2、有参数的装饰器 3、装饰器本身带参数的以及如果函数带return结果的情况的更多相关文章
- Python 装饰器(无参,有参、多重))
Python装饰器介绍 在Python中,装饰器(decorator)是在闭包的基础上发展起来的. 装饰器的实质是一个高阶函数,其参数是要装饰的函数名,其返回值是完成装饰的函数名,其作用是为已经存在的 ...
- Python带参数的装饰器
在装饰器函数里传入参数 # -*- coding: utf-8 -*- # 2017/12/2 21:38 # 这不是什么黑魔法,你只需要让包装器传递参数: def a_decorator_passi ...
- Python之函数的进阶(带参数的装饰器)
函数篇--装饰器二 带参数的装饰器 def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函 ...
- Python 带参数的装饰器 [2] 函数参数类型检查
在Python中,不知道函数参数类型是一个很正常的事情,特别是在一个大项目里.我见过有些项目里,每一个函数体的前十几行都在检查参数类型,这实在是太麻烦了.而且一旦参数有改动,这部分也需要改动.下面我们 ...
- Python_函数的有用信息、带参数的装饰器、多个装饰器装饰一个函数
函数的有用信息 代码1: def login(username, password): """ 此函数需要用户名,密码两个参数,完成的是登录的功能. :return: T ...
- python:带参数的装饰器,函数的有用信息
一.带参数的装饰器,函数的有用信息 def func1(): '''此函数的功能是完成的登陆的功能 return: 返回值是登陆成功与否(true,false) ''' print(333) func ...
- python 全栈开发,Day12(函数的有用信息,带参数的装饰器,多个装饰器装饰一个函数)
函数的执行时,*打散.函数的定义时,*聚合. from functools import wraps def wrapper(f): # f = func1 @wraps(f) def inner(* ...
- python 全栈开发,Day11(函数名应用,闭包,装饰器初识,带参数以及带返回值的装饰器)
一.函数名应用 函数名是什么?函数名是函数的名字,本质:变量,特殊的变量. 函数名(),执行此函数. python 规范写法 1. #后面加一个空格,再写内容,就没有波浪线了. 2.一行代码写完,下面 ...
- python全栈开发day12-函数的有用信息、带参数的装饰器、多个装饰器装饰一个函数、global和nonlocal的进一步解析和总结
1.上周回顾 1).函数名的应用 直接打印函数名,是函数的地址 变量 函数的参数 函数的返回值 可以当容器类数据类型的元素 2).闭包 内层函数对外层函数的非全局变量的引用,就是闭包. 并返回内部函数 ...
随机推荐
- CSS 技巧总结
CSS 技巧和经验列表 1. 如何清除图片下方出现的几像素的空白 方法一: img{display:block;} 方法二: img{vertical-align:top;} 除了top值,还可以设置 ...
- 关于EventBus3.0使用,你看这篇就够了
作为一枚Android开发者,关于EventBus相信应该都听说过.要是用过就请忽略本文,本文讲得比较基础. 要是没用过,建议你花两分钟看看. 目前EventBus最新版本是3.0,本demo基于3. ...
- ASP.NET动态创建数据库和表
using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; usin ...
- C++(十六) — 类中引用成员函数、命名空间的使用
1.为什么类中引用成员函数? 类将属性和方法做了封装.类是一种数据类型,也就是:固定大小内存块的别名. 类的定义是一个抽象的概念,定义时不分配内存,当用类定义对象时,才分配一个固定大小的内存块. 此时 ...
- 【scala】Option类型
一般来说,对于每种语言都会有一个关键字来表示一个对象引用的“无”.在Java中使用的是null. 而Scala则融合了函数式编程的风格,当预计到变量或者函数返回值可能不会引用任何值的时候,使用Opti ...
- Struts10---拦截器
01.创建一个登录界面 <%@ page language="java" import="java.util.*" pageEncoding=" ...
- TCPL学习笔记:4-12以及4-13。关于使用递归的问题。
4-12.写一个函数itoa,通过递归调用将整数转换成为字符串. #include <stdio.h> #include <stdlib.h> void Itoa(int nu ...
- Leetcode22. Generate Parentheses(生成有效的括号组合)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/74937307冷血之心的博客) 题目如下:
- [置顶]
【机器学习PAI实践四】如何实现金融风控
(本文数据为虚构,仅供实验) 一.背景 本文将针对阿里云平台上图算法模块来进行实验.图算法一般被用来解决关系网状的业务场景.与常规的结构化数据不同,图算法需要把数据整理成首尾相连的关系图谱.图算法更多 ...
- [置顶]
Android ShareSDKQQ 第三方登录so easy?
昨天群里有个群友看到我之前做的那个qq第三方登录怎么做的,于是乎思考了一下,还是决定写一篇博客记录下,其实都不难的,其实之前我又写到FaceBook的第三方登录不知道看下这Android集成FaceB ...