Python函数——装饰器
前言
给下面的函数加上运行时间
def fib(n):
a, b = 0, 1
for i in range(n):
print(b)
a, b = b, a+b
return b a = fib(50)
修改一:改动函数
import time def fib(n):
start = time.time()
a, b = 0, 1
for i in range(n):
print(b)
a, b = b, a+b
print(time.time() - start)
return b a = fib(50)
修改二:不改动函数
def fib(n):
a, b = 0, 1
for i in range(n):
print(b)
a, b = b, a+b
return b import time
def wrapper(func):
def inner(*args, **kwargs):
start = time.time()
a = func(*args, **kwargs)
print(time.time() - start)
return a
return inner # 返回函数名 fib = wrapper(fib)
fib(50)
忙活了这么半天,终于初具规模了!现在已经基本上完美了,唯一碍眼的那句话就是还要在做一次赋值调用。。。
装饰器
装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
装饰器的本质:就是一个闭包函数
满足开放封闭原则
1.对扩展是开放的
2.对修改是封闭的
通过使用装饰器语法糖来解决这个问题!
import time
def wrapper(func):
def inner(*args, **kwargs):
start = time.time()
a = func(*args, **kwargs)
print(time.time() - start)
return a
return inner # 返回函数名 @wrapper # fib = wrapper(fib)
def fib(n):
a, b = 0, 1
for i in range(n):
print(b)
a, b = b, a+b
return b fib(100)
上面的装饰器已经非常完美了,但是正常我们情况下查看函数的一些信息的方法在此处都会失效
import time
def wrapper(func):
def inner(*args, **kwargs):
start = time.time()
a = func(*args, **kwargs)
print(time.time() - start)
return a
return inner # 返回函数名 @wrapper # fib = wrapper(fib)
def fib(n):
a, b = 0, 1
for i in range(n):
print(b)
a, b = b, a+b
return b fib(100)
print(fib.__doc__)
print(fib.__name__) # 返回 inner # 为了不让他们失效,我们还要在装饰器上加上一点来完善它:
import time
from functools import wraps
def wrapper(func):
@wraps(func) # 加在最内层函数正上方
def inner(*args, **kwargs):
start = time.time()
a = func(*args, **kwargs)
print(time.time() - start)
return a
return inner # 返回函数名 @wrapper # fib = wrapper(fib)
def fib(n):
a, b = 0, 1
for i in range(n):
print(b)
a, b = b, a+b
return b fib(100)
print(fib.__doc__)
print(fib.__name__) # 返回 fib
带参数的装饰器
带参数的装饰器:就是给装饰器传参
用处:就是当加了很多装饰器的时候,现在忽然又不想加装饰器了,想把装饰器给去掉了,但是那么多的代码,一个一个的去闲的麻烦,
那么,我们可以利用带参数的装饰器去装饰它,这就他就像一个开关一样,要的时候就调用了,不用的时候就去掉了。给装饰器里面传个参数,
那么那个语法糖也要带个括号。在语法糖的括号内传参。在这里,我们可以用三层嵌套,弄一个标识 为去标识。如下面的代码示例
import time
from functools import wraps
flag = False def outer(flag):
def wrapper(func):
@wraps(func) # 加在最内层函数正上方
def inner(*args, **kwargs):
start = time.time()
if flag:
print('执行fib')
a = func(*args, **kwargs)
else:
print('不执行fib')
a = ''
print(time.time() - start)
return a
return inner # 返回函数名
return wrapper """
带参数的装饰器执行过程
fib = outer(False) (fib)
--分解
fib_decorator = outer(False)
fib = fib_decorator(fib)
--分解
fib_decorator = outer(False)
@fib_decorator
def fib(n)
所以,带参数的outer函数首先返回一个decorator函数,
再让这个decorator函数接收fib并返回新函数:
"""
@outer(True)
def fib(n):
a, b = 0, 1
for i in range(n):
print(b)
a, b = b, a+b
return b fib(100)
print(fib.__doc__)
print(fib.__name__) # 返回 fib
多个装饰器叠加使用
def decorator_a(func):
print('Get in decorator_a') def inner_a(*args, **kwargs):
print('Get in inner_a')
return func(*args, **kwargs)
return inner_a def decorator_b(func):
print('Get in decorator_b') def inner_b(*args, **kwargs):
print('Get in inner_b')
return func(*args, **kwargs)
return inner_b @decorator_b
@decorator_a
def f(x):
print('Get in f')
return x * 2 print(f(1))
输出结果分析
"""
装饰器执行顺序自下而上,内部函数调用顺序自上而下
所以输出
Get in decorator_a
Get in decorator_b
Get in inner_b
Get in inner_a
Get in f
2
分析
当解释器执行下面这段代码时,实际上按照从下到上的顺序已经依次调用了 decorator_a 和 decorator_b ,
这是会输出对应的 Get in decorator_a 和 Get in decorator_b 。
这时候 f 已经相当于 decorator_b 里的 inner_b 。但因为 f 并没有被调用,
所以 inner_b 并没有调用,依次类推 inner_b 内部的 inner_a 也没有调用,
所以 Get in inner_a 和 Get in inner_b 也不会被输出。
然后最后一行当我们对 f 传入参数1进行调用时, inner_b 被调用了,
它会先打印 Get in inner_b ,然后在 inner_b 内部调用了 inner_a
所以会再打印 Get in inner_a, 然后再 inner_a 内部调用的原来的 f,
并且将结果作为最终的返回。这时候你该知道为什么输出结果会是那样,
以及对装饰器执行顺序实际发生了什么有一定了解了吧。
"""
装饰器使用举例
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2018/4/4 22:38
# @Author : hyang
# @Site :
# @File : 装饰器练习.py
# @Software: PyCharm """
三:编写装饰器,为函数加上认证的功能,即要求认证成功后才能执行函数
四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),
要求登录成功一次,后续的函数都无需再输入用户名和密码
提示:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式
""" user_data = {
'user': None,
'is_authenticated': False
} def login_required(func):
# 用户认证装饰器
def inner(*args, **kwargs):
if args[0].get('is_authenticated'):
print('User is authenticated')
ret = func(*args, **kwargs)
else:
exit("User is not authenticated !!!")
return ret
return inner def get_acct_info():
"""
get acct_info from USER.TXT
:return:
"""
with open(r'USER.TXT', 'r') as f:
for line in f:
user_dict = eval(line)
USER_INFO_LI.append(user_dict) def auth_user():
"""
认证用户
:return:
"""
count = 0
while count < 3:
user = input('user >>> ').strip()
pwd = input('pwd >>> ').strip()
# print(USER_INFO_LI)
user_flag = False
pwd_flag = False
for item in USER_INFO_LI:
if user == item['name']:
user_flag = True
if user_flag:
if pwd == item['password']:
pwd_flag = True
if user_flag and pwd_flag:
# 用户认证成功
user_data['user'] = user
user_data['is_authenticated'] = True
print('account login success')
return user_data
elif user_flag:
# 密码不对
print('pwd is error')
else:
# 用户名不存在
print('user is not exists')
count += 1
else:
print("account [%s] too many login attempts" % user)
exit() @login_required
def print_info(p_data):
print(p_data) @login_required
def enter_x(p_data):
print('enter_x', p_data['user']) @login_required
def enter_y(p_data):
print('enter_x', p_data['user']) def logout(p_data):
print('logout', p_data['user'])
p_data['is_authenticated'] = False def interactive(p_data):
"""
interact with user
:return: """
menu = """
------- menu ---------
1. 账户信息(功能已实现)
2. 进入x(功能已实现)
3. 进入y(功能已实现)
4. 退出程序
"""
print(menu)
menu_dic = {
'': print_info,
'': enter_x,
'': enter_y,
'': logout
}
exit_flag = False
while not exit_flag:
user_option = input(">>:").strip()
if user_option in menu_dic:
menu_dic[user_option](p_data)
else:
print("Option does not exist!") if __name__ == '__main__':
USER_INFO_LI = []
get_acct_info()
acc_data = auth_user()
interactive(acc_data)
Python函数——装饰器的更多相关文章
- Python函数装饰器原理与用法详解《摘》
本文实例讲述了Python函数装饰器原理与用法.分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值 ...
- python函数-装饰器
python函数-装饰器 1.装饰器的原则--开放封闭原则 开放:对于添加新功能是开放的 封闭:对于修改原功能是封闭的 2.装饰器的作用 在不更改原函数调用方式的前提下对原函数添加新功能 3.装饰器的 ...
- Python函数装饰器高级用法
在了解了Python函数装饰器基础知识和闭包之后,开始正式学习函数装饰器. 典型的函数装饰器 以下示例定义了一个装饰器,输出函数的运行时间: 函数装饰器和闭包紧密结合,入参func代表被装饰函数,通过 ...
- Python 函数装饰器
首次接触到装饰器的概念,太菜啦! Python 装饰器可以大大节省代码的编写量,提升代码的重复使用率.函数装饰器其本质也是一个函数,我们可以把它理解为函数中定义了一个子函数. 例如我们有这么一个需求, ...
- Python @函数装饰器及用法
1.函数装饰器的工作原理 函数装饰器的工作原理是怎样的呢?假设用 funA() 函数装饰器去装饰 funB() 函数,如下所示: #funA 作为装饰器函数 def funA(fn): #... fn ...
- Python @函数装饰器及用法(超级详细)
函数装饰器的工作原理是怎样的呢?假设用 funA() 函数装饰器去装饰 funB() 函数,如下所示: #funA 作为装饰器函数 def funA(fn): #... fn() # 执行传入的fn参 ...
- Python高手之路【四】python函数装饰器
def outer(func): def inner(): print('hello') print('hello') print('hello') r = func() print('end') p ...
- python 函数 装饰器 内置函数
函数 装饰器 内置函数 一.命名空间和作用域 二.装饰器 1.无参数 2.函数有参数 3.函数动态参数 4.装饰器参数 三.内置函数 salaries={ 'egon':3000, 'alex':10 ...
- Python 函数装饰器简明教程
定义类的静态方法时,就使用了装饰器.其实面向对象中的静态方法都是使用了装饰器. @staticmethod def jump(): print(" 3 meters high") ...
- Python高手之路【四】python函数装饰器,迭代器
def outer(func): def inner(): print('hello') print('hello') print('hello') r = func() print('end') p ...
随机推荐
- eosjs
[eosjs] Javascript API,用于帮助访问与 EOSIO RPC API. 1.安装 npm install eosjs@beta 2.Signature Provider The S ...
- angular分页插件tm.pagination二次触发问题解决歪方案
今天在学习angularjs的分页插件时遇到了一个前端的问题,谷歌浏览器开发者模式调试的时候发现每次点击分页刷新按钮会触发两次后台请求,ajax向后台发送了两次请求,这对于强迫症患者来说是一个比较恶心 ...
- C++ 获取字符串中的所有汉字
#include<iostream> using namespace std; int main() { char str[20] = "cd大家好df"; ...
- java_14 Date
1.Date类的构造方法 Date是表示时间的类 空参构造 public Date() public class Demo { public static void main(String[] arg ...
- Linux的php-fpm优化心得-php-fpm进程占用内存大和不释放内存问题(转)
原文地址:https://wzfou.com/php-fpm/ 最近发现博客的内存老是隔三差五地被“吃掉”了,登录到后台后偶尔会出卡顿的情况,一开始怀疑是Swap不够导致的,于是给VPS主机增加了几个 ...
- PHP开发——分支结构
If if if···else··· if···else··· switch
- MyBatis-Plus 多库部署方式;spring mvc 多库部署方式
1.实现mybatis-plus的多个数据库的切换方式 源码地址:https://github.com/baomidou/mybatisplus-spring-mvc 2.因为其文档都是相互依赖的,所 ...
- __LINE__的用法
简单的说,__LINE__可以获取当前代码的函数,结合__FUNCTION__可以打印调试信息,比如函数出错时运行的函数名,及行号,例如 #define p_err_fun , os_time_get ...
- windows下angularJs环境搭建和遇到的问题解决
搭建本地开发环境 angular官网社区上说:你应该在自己的电脑上本地开发... 你也应该在本地环境学习 Angular. 本人也认为在本地搭建学习环境--靠谱.所以决定尝试一下. 安照中文社区给的步 ...
- PowerShell工作流学习-1-嵌套工作流和嵌套函数
关键点: a)嵌套深度没有任何语法限制,但是嵌套三个层次的工作流不支持任何通用参数,包括工作流通用参数 b)嵌套工作流可以调用当前范围和任何父范围内的工作流和函数 c)工作流不允许递归调用,脚本和函数 ...