装饰器:以某种方式增强函数。
两大特性:1、可以将被装饰的函数替换成其他函数。
2、在加载模块时立即执行。

案例1
def make_avarage():
count=0
total=0
def averager(new_value):
count+=1
total+=new_value
return total/count
return averager
这里会报错,averager里面是一个新的 count、total变量

案例2
使用nolocal作用:将变量标记为自由变量,
def make_avarage():
count=0
total=0
def averager(new_value):
nonlocal count,total
count+=1
total+=new_value
return total/count
return averager

案例3
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun May 3 23:27:22 2020 @author: root
""" promos=[]
def promotion(promo_func):
promo.append(promo_func)
return promo_func @promotion
def FidelityPromo(order):
return order.total()*0.05 if order.customer.fidelity>=1000 else 0 @promotion
def BulkItemPromo(order):
discount = 0
for item in order.cart:
if item.quantity>=20:
discount+=item.total()*0.1
return discount @promotion
def LargeOrderPromo(order):
discount_items = {item.product for item in order.cart}
if len(discount_items)>=10:
return order.total()*0.07
return 0 def best_promo(order):
return max(promo(order) for promo in promos)

二、@property:方法伪装属性,方法返回值及属性值,被装饰方法不能有参数,必须实例化后调用,类不能调用
#@ property
#将一个方法伪装成属性,被修饰的特性方法,内部可以实现处理逻辑,但对外提供统一的调用方式,实现一个实例属性的

getter
setter
d elete
三种方法的内部逻辑,具体含义看示
class Data:

    def __init__(self):
self.number = 123 @property
def operation(self):
return self.number

@operation.getter
def operation(self):
return self.number @operation.setter
def operation(self, number):
self.number = number @operation.deleter
def operation(self):
del self.number

案例1----普通写法
class Student(object):
def get_score(self):
return self._score

def set_score(self,value):
if not isinstance(value,int):
raise ValueError('pppppp')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value

Python内置的@property装饰器就是负责把一个方法变成属性调用
案例1----装饰器写法


class Student(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('pppppp')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value
s=Student()
s.score=60
s.score=9999
print (s.score)

三、类装饰器:类装饰器使用地方较少,核心是通过复写类的回调方法call.

装饰器应用场景:

1、引入日志
2、函数执行时间统计
3、执行函数前预备处理
执行函数后清理功能
权限校验等场景
缓存

方法:__call__
__call__ 方法,不得不先提到一个概念,就是可调用对象(callable),我们平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable
class Add:

def __init__(self, fn):
print("初始化")
self.num = 44
self.fn = fn

def __call__(self, *args, **kwargs):
print("类装饰器开始工作")
return self.fn(self.num)

@Add
def test(n):
return 4+n

if __name__ == '__main__':
num = test()
print(num)

结果:
初始化
<function test at 0x7f95f883bc20>
类装饰器开始工作
44
48
 
 

案例1

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May 4 22:11:44 2020 @author: root
简单注册表
""" funcs = []
def register(func):
funcs.append(func)
return func @register
def a():
return 3 @register
def b():
return 5 def c():
return 8 # 访问结果
result = [func() for func in funcs]
print(funcs)
print(result) # [<function a at 0x7f95f8837050>, <function b at 0x7f95f8837290>]
# [3, 5]

案例2

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May  4 22:14:37 2020

@author: root

注册表隔离(使用类的不同实例)
"""

class Registry(object):
    def __init__(self):
        self._funcs=[]

    def register(self,func):
        self._funcs.append(func)

    def run_all(self):
        return [func() for func in self._funcs]

r1=Registry()
r2=Registry()

@r1.register
def a():
    return 3

@r2.register
def b():
    return 5

案例3

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May 4 22:30:41 2020 @author: root 用户验证
""" from functools import wraps class User(object):
def __init__(self, username, email):
self.username = username
self.email = email class AnonymousUser(object):
def __init__(self):
self.username = self.email = None def __nonzero__(self): # 将对象转换为bool类型时调用
return False def requires_user(func):
@wraps(func)
def inner(user, *args, **kwargs): # 由于第一个参数无法支持self, 该装饰器不支持装饰类
if user and isinstance(user, User):
return func(user, *args, **kwargs)
else:
raise ValueError("非合法用户")
return inner a=User('teddy', '120@163.com')
print (a)

案例3

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May 4 22:36:47 2020 @author: root 异常捕获
""" import json
from functools import wraps class Error1(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg def json_output(func):
@wraps(func)
def inner(*args, **kwargs):
try:
result = func(*args, **kwargs)
except Error1 as ex:
result = {"status": "error", "msg": str(ex)}
return json.dumps(result)
return inner # 使用方法
@json_output
def error():
raise Error1("该条异常会被捕获并按JSON格式输出")

案例3

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May 4 22:40:47 2020 @author: root 日志管理
"" import time
import logging
from functools import wraps def logged(func):
@wraps(func)
def inner(*args, **kwargs): # *args可以装饰函数也可以装饰类
start = time.time()
result = func(*args, **kwargs)
exec_time = time.time() - start
logger = logging.getLoger("func.logged")
logger.warning("{} 调用时间:{:.2} 执行时间:{:.2}s 结果:{}".format(func.__name__, start, exec_time, result))
资源清理#import pymysql

class DBConnection(object):
def __init__(self, *args, **kwargs):
self.args,self.kwargs = args, kwargs def __enter__(self):
self.conn = pymysql.connect(*args, **kwargs)
return self.conn.cursor() def __exit__(self, exc_type, exc_instance, trackback):
self.conn.close()
 案例来源:https://www.cnblogs.com/superhin/p/11454823.html

流畅的python--装饰器的更多相关文章

  1. Python装饰器:套层壳我变得更强了

    Python装饰器:套层壳我变得更强了 Python装饰器:套层壳我变得更强了 关于作用域和闭包可以聊点什么? 什么是作用域 什么是闭包 装饰器:套层壳我变得更强了 参考资料 昨天阅读了<Pyt ...

  2. 关于python装饰器

    关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...

  3. python装饰器通俗易懂的解释!

    1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...

  4. Python 装饰器学习

    Python装饰器学习(九步入门)   这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...

  5. python 装饰器修改调整函数参数

    简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...

  6. python 装饰器学习(decorator)

    最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initi ...

  7. Python装饰器详解

    python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...

  8. 关于python装饰器(Decorators)最底层理解的一句话

    一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.h ...

  9. Python装饰器由浅入深

    装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...

  10. Python装饰器与面向切面编程

    今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数 ...

随机推荐

  1. go-zero:开箱即用的微服务框架

    go-zero 是一个集成了各种工程实践的 Web 和 rpc 框架,它的弹性设计保障了大并发服务端的稳定性,并且已经经过了充分的实战检验. go-zero 在设计时遵循了 "工具大于约定和 ...

  2. 一、部署监控服务器--安装LNMP环境

    1.要求: 本案例要求部署-台Zabbix监控服务器, -台被监控主机,为进一步执行具体的监控任务做准备:1.安装LNMP环境2.源码安装Zabbix3.安装监控端主机,修改基本配置4.初始化Zabb ...

  3. 前台使用Vue

    前台搭建遇到问题 ----前台访问量大 未采用vue 单页面SAP 的方式构建 使用多HTML构建页面 项目构建 vue 2.6 https://cn.vuejs.org/ elementUI htt ...

  4. Oracle对大表进行delete注意事项

    如果对大表进行大量的delete和update,那么可以注意一下如下说明: (1) 查看执行计划,如果说删除的记录很多,走索引的成本会比全表扫描更大,因为更新数据时还需要做一些约束校验和创建index ...

  5. 迁移Report Server DataBase时遇到的坑

    1.项目背景 由于历史原因,公司部分系统的Report是基于SQL Server Report Service搭建的,且Reporting Services 和Report Server DataBa ...

  6. No serializer found for class com.bean.user and no properties discovered to create BeanSerializer

    解决方法: 方法1:将bean目录下的实体类属性由private改为public(不推荐): 方法2:给实体类属性设置setter和getter方法(推荐使用).

  7. 3、SpringBoot整合之SpringBoot整合JDBC

    SpringBoot整合JDBC 一.创建SpringBoot项目 选择Spring Web.JDBC API.MySQL Driver 二.在pom配置文件中修改JDBC版本,导入lombok &l ...

  8. 7、resync实时备份

    sersync+rsync(增量,无差异备份),resync支持多线程,效果比inotify更好,配置思想和inotify很相似 7.1.在备份服务器上安装并配置rsync服务,实现nfs共享目录,可 ...

  9. elk 日志收集 filebeat 集群搭建 php业务服务日志 nginx日志 json 7.12版本 ELK 解决方案

    难的不是技术,难的是业务.熟悉业务流程才是最难的. 其实搜索进来的每一个人的需求不一样,希望你能从我的这篇文章里面收获到. 建议还是看官方文档,更全面一些. 一.背景 1,收集nginx  acces ...

  10. 在docker中使用nginx部署前端项目

    前言 部署了三个nginx用于前端项目, 并使用keepalived部署好热备, 所以总共有5个nginx 创建好nginx的文件和配置 根据上面的指令创建好目录 mkdir /home/web/ng ...