python 装饰器的缺点以及解决方法
1.python装饰器的缺点
装饰器可以允许我们在不改变函数或犯方法的调用方式的情况下,添加额外的功能;
如下所示,我们要在中的方法之前增加装饰器check_is_admin,用来判断执行类的方法的用户是否为admin用户;
def check_is_admin(f):
def wrapper(*args,**kwargs):
if kwargs.get('username') != 'admin':
raise Exception("This user is not allowed to get food")
return f(*args,**kwargs)
return wrapper class store(object):
@check_is_admin
def get_food(self,username,food):
return self.storage.get(food) @check_is_admin
def put_food(self,username,food):
self.storage.put(food)
但是,经过装饰器修饰的函数,其func_name和func_doc的属性都会丢失;
如下:
def foobar(username="someone"):
"""Do crzay staff."""
pass
print foobar.func_doc
print foobar.func_name 执行结果为:
Do crzay staff.
foobar
如果给上述函数增加装饰器呢?
def is_admin(f):
def wrapper(*args,**kwargs):
if kwargs.get(*args,**kwargs):
raise Exception("This user is not allowed to get food")
return f(*args,**kwargs)
return wrapper @is_admin
def foobar(username="someone"):
"""Do crazy staff"""
pass
print foobar.__doc__
print foobar.__name__ 执行结果为:
None
wrapper
update_wapper的源码如下:
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
WRAPPER_UPDATES = ('__dict__',)
def update_wrapper(wrapper,
wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
"""Update a wrapper function to look like the wrapped function
wrapper is the function to be updated
wrapped is the original function
assigned is a tuple naming the attributes assigned directly
from the wrapped function to the wrapper function (defaults to
functools.WRAPPER_ASSIGNMENTS)
updated is a tuple naming the attributes of the wrapper that
are updated with the corresponding attribute from the wrapped
function (defaults to functools.WRAPPER_UPDATES)
"""
for attr in assigned:
setattr(wrapper, attr, getattr(wrapped, attr))
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
# Return the wrapper so this can be used as a decorator via partial()
return wrapper
2.解决方案
使用functools的update_wrapper函数可以解决该问题
如下:
def is_admin(f):
def wrapper(*args,**kwargs):
if kwargs.get(*args,**kwargs):
raise Exception("This user is not allowed to get food")
return f(*args,**kwargs)
return wrapper def foobar(username="someone"):
"""Do crazy staff"""
pass import functools
foobar = functools.update_wrapper(is_admin,foobar)
print foobar.__name__
print foobar.__doc__ 执行结果如下:
foobar
Do crazy staff
但是上述方式手工调用装饰器不太方便,我们在这里使用functools.warps的装饰器
import functools def is_admin(f):
@functools.wraps(f)
def wrapper(*args,**kwargs):
if kwargs.get(*args,**kwargs):
raise Exception("This user is not allowed to get food")
return f(*args,**kwargs)
return wrapper @is_admin
def foobar(username="someone"):
"""Do crazy staff"""
pass
print foobar.__doc__
print foobar.__name__ 执行结果为:
Do crazy staff #####
foobar
结论:python的装饰器会导致被修饰函数的__doc__,__name__等属性丢掉,如果要保留函数的这些属性,需要在装饰器函数中添加functools.wrap装饰器;
python 装饰器的缺点以及解决方法的更多相关文章
- python 装饰器修改调整函数参数
简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...
- Flask(2)- 装饰器的坑及解决办法、flask中的路由/实例化配置/对象配置/蓝图/特殊装饰器(中间件、重定义错误页面)
一.装饰器的坑以及解决方法 1.使用装饰器装饰两个视图函数,代码如下 from flask import Flask, redirect, render_template, request, sess ...
- Python 装饰器装饰类中的方法
title: Python 装饰器装饰类中的方法 comments: true date: 2017-04-17 20:44:31 tags: ['Python', 'Decorate'] categ ...
- python装饰器方法
前几天向几位新同事介绍项目,被问起了@login_required的实现,我说这是django框架提供的装饰器方法,验证用户是否登录,只要这样用就行了,因为自己不熟,并没有做过多解释. 今天查看dja ...
- python 装饰器 一篇就能讲清楚
装饰器一直是我们学习python难以理解并且纠结的问题,想要弄明白装饰器,必须理解一下函数式编程概念,并且对python中函数调用语法中的特性有所了解,使用装饰器非常简单,但是写装饰器却很复杂.为了讲 ...
- 理解 Python 装饰器看这一篇就够了
讲 Python 装饰器前,我想先举个例子,虽有点污,但跟装饰器这个话题很贴切. 每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?我们想到的一个办法就是把内裤改造一下,让它 ...
- python装饰器的作用
常见装饰器:内置装饰器:类装饰器.函数装饰器.带参数的函数装饰器 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常 ...
- Python装饰器基础
一.Python装饰器引入 讲 Python 装饰器前,我想先举个例子,虽有点污,但跟装饰器这个话题很贴切. 每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?我们想到的一个 ...
- python装饰器通俗易懂的解释!
1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...
随机推荐
- python学习笔记之一
1.可以自己运行,也可以被import后调用 if __name__ == '__main__' main() 2.可变参数,关键字参数,命名关键字参数 可变参数和关键字参数 def f1(a, b, ...
- 06 I/O重定向与管道符
首先,我们知道我们的计算机结构,在第一节的时候已经介绍过了,CPU进行数据运算,同时控制器负责指令的发送,而内存则是数据存储的地方,CPU读取的数据均从内存中调取.电脑除了CPU和内存外,我们还有I/ ...
- django练习题
1.Web框架的本质是什么?为什么要有Web框架? 所有的Web应用,本质上其实就是一个socket服务端,用户端程序其实就是一个socket客户端.对于真实开发中的python web程序来说,一般 ...
- bootstrap4学习—Bootstrap v4.0.0-alpha.6的快速参考
下面为Bootstrap v4.0.0-alpha.6中的代码快速检索地址: 网址:https://hackerthemes.com/bootstrap-cheatsheet/ 在使用bootstra ...
- Linux性能优化 第七章 性能工具:网络
7.1 网络I/O介绍 Linux和其他主流操作系统中的网络流量被抽象为一系列的硬件和软件层次. 链路层,也就是最低的一层,包含网络硬件,如以太网设备.在传送网络流量时,这一层并不区分流量类型,而仅仅 ...
- Android最新版支付宝支付集成
上次集成支付宝支付已经很久了,今天写东西用到了支付宝支付,就大致写一下流程: 去蚂蚁金服下载最新版的Android&IOS端SDK 全部文档 -- 资源下载 -- App支付客户端 下载后解压 ...
- mybatis基于注解形式的多数据源
最近在做一个系统管理项目,需要使用到多数据源,尝试了注解形式和xml形式的多数据源配置,以下是基于注解形式的Mybatis多数据源配置. 1.application.yml 配置文件 database ...
- python项目入门之 安装、创建
3年前接触python,那时候还是文本格式进行学习,但是由于一直没有项目实践,所以就搁浅了 今天,python如火如荼,适用于人工智能等多领域,已经成为了语言界的翘楚 python有非常多的优点,开源 ...
- redis下操作hash对象
redis下操作hash对象 hash用于存储对象,对象的格式为键值对 命令 设置 设置单个属性 HSET key field value 设置多个属性 HMSET key field value [ ...
- Apache- DBUtils框架学习
一.DBUtils DBUtils 的介绍 commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,,DBUtils封装了对JDBC的操作,简 ...