1、一些装饰器,可以减少重复编写。比较常用的。

用的时候函数上面加上装饰器就可以。这是一些装饰器,加在函数或者方法上,减少了很多重复代码。

除此之外工作中也用一些mixin类大幅减少代码。

import sys
import traceback
from functools import wraps
import threading
import time
import unittest
from app.utils_ydf import LogManager
from tomorrow3 import threads as tomorrow_threads
from functools import lru_cache # NOQA handle_exception_log = LogManager('function_error').get_logger_and_add_handlers()
run_times_log = LogManager('run_many_times').get_logger_and_add_handlers() class CustomException(Exception):
def __init__(self, err=''):
err0 = 'fatal exception\n'
Exception.__init__(self, err0 + err) def run_many_times(times=1):
"""把函数运行times次的装饰器
:param times:运行次数
没有捕获错误,出错误就中断运行,可以配合handle_exception装饰器不管是否错误都运行n次。
""" def _run_many_times(func):
@wraps(func)
def __run_many_times(*args, **kwargs):
for i in range(times):
LogManager('run_many_times').get_logger_without_handlers().debug('* ' * 50 + '当前是第 {} 次运行[ {} ]函数'.format(i + 1, func.__name__))
func(*args, **kwargs) return __run_many_times return _run_many_times def handle_exception(retry_times=0, error_detail_level=0, is_throw_error=False):
"""捕获函数错误的装饰器,重试并打印日志
:param retry_times : 重试次数
:param error_detail_level :为0打印exception提示,为1打印3层深度的错误堆栈,为2打印所有深度层次的错误堆栈
:param is_throw_error : 在达到最大次数时候是否重新抛出错误
:type error_detail_level: int
"""
if error_detail_level not in [0, 1, 2]:
raise Exception('error_detail_level参数必须设置为0 、1 、2') def _handle_exception(func):
@wraps(func)
def __handle_exception(*args, **keyargs):
for i in range(0, retry_times + 1):
try:
result = func(*args, **keyargs)
if i:
LogManager('function_error').get_logger_without_handlers().debug(
u'%s\n调用成功,调用方法--> [ %s ] 第 %s 次重试成功' % ('# ' * 40, func.__name__, i))
return result except Exception as e:
error_info = ''
if error_detail_level == 0:
error_info = str(e)
elif error_detail_level == 1:
error_info = traceback.format_exc(limit=3)
elif error_detail_level == 2:
error_info = traceback.format_exc() LogManager('function_error').get_logger_without_handlers().error(
u'%s\n记录错误日志,调用方法--> [ %s ] 第 %s 次错误重试,错误原因是: %s\n' % ('- ' * 40, func.__name__, i, error_info))
if i == retry_times and is_throw_error: # 达到最大错误次数后,重新抛出错误
raise e return __handle_exception return _handle_exception def keep_circulating(time_sleep=0.001):
"""间隔一段时间,一直循环运行某个方法的装饰器
:param time_sleep :循环的间隔时间
"""
if not hasattr(keep_circulating, 'keep_circulating_log'):
keep_circulating.log = LogManager('keep_circulating').get_logger_and_add_handlers() def _keep_circulating(func):
@wraps(func)
def __keep_circulating(*args, **kwargs):
while 1:
try:
func(*args, **kwargs)
except Exception:
msg = func.__name__ + ' 运行出错\n ' + traceback.format_exc(limit=2)
keep_circulating.log.error(msg)
finally:
time.sleep(time_sleep) return __keep_circulating return _keep_circulating def singleton(cls):
"""单例模式装饰器
"""
_instance = {} @wraps(cls)
def _singleton(*args, **kwargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kwargs)
return _instance[cls] return _singleton def timer(func):
"""计时器装饰器,只能用来计算函数运行时间"""
if not hasattr(timer, 'log'):
timer.log = LogManager('timer').get_logger_and_add_handlers() @wraps(func)
def _timer(*args, **kwargs):
t1 = time.time()
result = func(*args, **kwargs)
t2 = time.time()
t_spend = t2 - t1
timer.log.debug('执行[ {} ]方法用时 {} 秒'.format(func.__name__, t_spend))
return result return _timer class TimerContextManager(object):
"""
用上下文管理器计时,可对代码片段计时
"""
log = LogManager('TimerContext').get_logger_and_add_handlers() def __init__(self, is_print_log=True):
self._is_print_log = is_print_log
self.t_spend = None
self._line = None
self._file_name = None
self.time_start = None def __enter__(self):
self._line = sys._getframe().f_back.f_lineno # 调用此方法的代码的函数
self._file_name = sys._getframe(1).f_code.co_filename # 哪个文件调了用此方法
self.time_start = time.time()
return self def __exit__(self, exc_type, exc_val, exc_tb):
self.t_spend = time.time() - self.time_start
if self._is_print_log:
self.log.debug(f'对下面代码片段进行计时: \n执行"{self._file_name}:{self._line}" 用时 {self.t_spend} 秒') class ExceptionContextManager():
"""
用上下文管理器捕获异常,可对代码片段进行错误捕捉,比装饰器更细腻
""" def __init__(self, logger_name='ExceptionContextManager', verbose=100, donot_raise__exception=True, ):
"""
:param _verbose: 打印错误的深度,对应traceback对象的limit,为正整数
:param donot_raise__exception:是否不重新抛出错误,为Fasle则抛出,为True则不抛出
"""
self.logger = LogManager(logger_name).get_logger_and_add_handlers()
self._verbose = verbose
self._donot_raise__exception = donot_raise__exception def __enter__(self):
return self def __exit__(self, exc_type, exc_val, exc_tb):
# print(exc_val)
# print(traceback.format_exc())
exc_str = str(exc_type) + ' : ' + str(exc_val)
exc_str_color = '\033[0;30;45m%s\033[0m' % exc_str
if self._donot_raise__exception:
if exc_tb is not None:
self.logger.error('\n'.join(traceback.format_tb(exc_tb)[:self._verbose]) + exc_str_color)
return self._donot_raise__exception # __exit__方法必须retuen True才会不重新抛出错误 def where_is_it_called(func):
"""一个装饰器,被装饰的函数,如果被调用,将记录一条日志,记录函数被什么文件的哪一行代码所调用"""
if not hasattr(where_is_it_called, 'log'):
where_is_it_called.log = LogManager('where_is_it_called').get_logger_and_add_handlers() @wraps(func)
def _where_is_it_called(*args, **kwargs):
# 获取被调用函数名称
# func_name = sys._getframe().f_code.co_name
func_name = func.__name__
# 什么函数调用了此函数
which_fun_call_this = sys._getframe(1).f_code.co_name # NOQA # 获取被调用函数在被调用时所处代码行数
line = sys._getframe().f_back.f_lineno # 获取被调用函数所在模块文件名
file_name = sys._getframe(1).f_code.co_filename where_is_it_called.log.debug('文件[{}]的第[{}]行即模块 [{}] 中的方法 [{}] 正在被文件 [{}] 中的方法 [{}] 中的第 [{}] 行处调用,' \
'传入的参数为[{args},{kwargs}]'.format(func.__code__.co_filename, func.__code__.co_firstlineno, func.__module__, func_name, file_name, which_fun_call_this, line,
args=args, kwargs=kwargs))
try:
t0 = time.time()
result = func(*args, **kwargs)
t_spend = round(time.time() - t0, 2)
where_is_it_called.log.debug('执行函数[{}]消耗的时间是{}秒,返回的结果是 --> '.format(func_name, t_spend) + str(result))
return result
except Exception as e:
where_is_it_called.log.debug('执行函数{},发生错误'.format(func_name))
raise e return _where_is_it_called class cached_class_property(object):
"""类属性缓存装饰器""" def __init__(self, func):
self.func = func def __get__(self, obj, cls):
if obj is None:
return self
value = self.func(obj)
setattr(cls, self.func.__name__, value)
return value class cached_property(object):
"""实例属性缓存装饰器""" def __init__(self, func):
self.func = func def __get__(self, obj, cls):
print(obj, cls)
if obj is None:
return self
value = obj.__dict__[self.func.__name__] = self.func(obj)
return value def cached_method_result(fun):
"""方法的结果装饰器,不接受self以外的多余参数,主要用于那些属性类的property方法属性上""" @wraps(fun)
def inner(self):
if not hasattr(fun, 'result'):
result = fun(self)
fun.result = result
fun_name = fun.__name__
setattr(self.__class__, fun_name, result)
setattr(self, fun_name, result)
return result
else:
return fun.result return inner class FunctionResultCacher:
logger = LogManager('FunctionResultChche').get_logger_and_add_handlers()
func_result_dict = {}
"""
{
(f1,(1,2,3,4)):(10,1532066199.739),
(f2,(5,6,7,8)):(26,1532066211.645),
}
""" @classmethod
def cached_function_result_for_a_time(cls, cache_time):
"""
函数的结果缓存一段时间装饰器,不要装饰在返回结果是超大字符串或者其他占用大内存的数据结构上的函数上面。
:param cache_time :缓存的时间
:type cache_time : float
""" def _cached_function_result_for_a_time(fun): @wraps(fun)
def __cached_function_result_for_a_time(*args, **kwargs):
# print(cls.func_result_dict)
# if len(cls.func_result_dict) > 1024:
if sys.getsizeof(cls.func_result_dict) > 10 * 1000 * 1000:
cls.func_result_dict.clear() key = cls._make_arguments_to_key(args, kwargs)
if (fun, key) in cls.func_result_dict and time.time() - cls.func_result_dict[(fun, key)][1] < cache_time:
return cls.func_result_dict[(fun, key)][0]
else:
result = fun(*args, **kwargs)
cls.func_result_dict[(fun, key)] = (result, time.time())
cls.logger.debug('函数 [{}] 此次不使用缓存'.format(fun.__name__))
return result return __cached_function_result_for_a_time return _cached_function_result_for_a_time @staticmethod
def _make_arguments_to_key(args, kwds):
key = args
if kwds:
sorted_items = sorted(kwds.items())
for item in sorted_items:
key += item
return key class __KThread(threading.Thread):
def __init__(self, *args, **kwargs):
threading.Thread.__init__(self, *args, **kwargs)
self.killed = False
self.__run_backup = None def start(self):
"""Start the thread."""
self.__run_backup = self.run
self.run = self.__run # Force the Thread to install our trace.
threading.Thread.start(self) def __run(self):
"""Hacked run function, which installs the trace."""
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup def globaltrace(self, frame, why, arg):
if why == 'call':
return self.localtrace
return None def localtrace(self, frame, why, arg):
if self.killed:
if why == 'line':
raise SystemExit()
return self.localtrace def kill(self):
self.killed = True class TIMEOUT_EXCEPTION(Exception):
"""function run timeout"""
pass def timeout(seconds):
"""超时装饰器,指定超时时间 若被装饰的方法在指定的时间内未返回,则抛出Timeout异常""" def timeout_decorator(func): def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):
result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs)) def _(*args, **kwargs):
result = []
new_kwargs = { 'oldfunc': func,
'result': result,
'oldfunc_args': args,
'oldfunc_kwargs': kwargs
} thd = __KThread(target=_new_func, args=(), kwargs=new_kwargs)
thd.start()
thd.join(seconds)
alive = thd.isAlive()
thd.kill() # kill the child thread if alive:
raise TIMEOUT_EXCEPTION(
'function run too long, timeout %d seconds.' % seconds)
else:
if result:
return result[0]
return result _.__name__ = func.__name__
_.__doc__ = func.__doc__
return _ return timeout_decorator class _Test(unittest.TestCase):
@unittest.skip
def test_superposition(self):
"""测试多次运行和异常重试,测试装饰器叠加""" @run_many_times(3)
@handle_exception(2, 1)
def f():
import json
json.loads('a', ac='ds') f() @unittest.skip
def test_handle_exception(self):
"""测试异常重试装饰器"""
import requests @handle_exception(2)
def f3():
pass
requests.get('dsdsdsd') f3() @unittest.skip
def test_run_many_times(self):
"""测试运行5次""" @run_many_times(5)
def f1():
print('hello')
time.sleep(1) f1() @unittest.skip
def test_tomorrow_threads(self):
"""测试多线程装饰器,每2秒打印5次""" @tomorrow_threads(5)
def f2():
print(time.strftime('%H:%M:%S'))
time.sleep(2) [f2() for _ in range(9)] @unittest.skip
def test_singleton(self):
"""测试单例模式的装饰器""" @singleton
class A(object):
def __init__(self, x):
self.x = x a1 = A(3)
a2 = A(4)
self.assertEqual(id(a1), id(a2))
print(a1.x, a2.x) @unittest.skip
def test_keep_circulating(self):
"""测试间隔时间,循环运行""" @keep_circulating(3)
def f6():
print("每隔3秒,一直打印 " + time.strftime('%H:%M:%S')) f6() @unittest.skip
def test_timer(self):
"""测试计时器装饰器""" @timer
def f7():
time.sleep(2) f7() @unittest.skip
def test_timer_context(self):
"""
测试上下文,对代码片段进行计时
"""
with TimerContextManager(is_print_log=False) as tc:
time.sleep(2)
print(tc.t_spend) @unittest.skip
def test_where_is_it_called(self):
"""测试函数被调用的装饰器,被调用2次将会记录2次被调用的日志""" @where_is_it_called
def f9(a, b):
result = a + b
print(result)
time.sleep(0.1)
return result f9(1, 2) f9(3, 4) @unittest.skip
def test_cached_function_result(self):
@FunctionResultCacher.cached_function_result_for_a_time(3)
def f10(a, b, c=3, d=4):
print('计算中。。。')
return a + b + c + d print(f10(1, 2, 3, 4))
print(f10(1, 2, 3, 4))
time.sleep(4)
print(f10(1, 2, 3, 4)) @unittest.skip
def test_exception_context_manager(self):
def f1():
1 + '' def f2():
f1() def f3():
f2() def f4():
f3() def run():
f4() with ExceptionContextManager() as ec:
run() print('finish') def test_timeout(self):
"""
测试超时装饰器
:return:
""" @timeout(3)
def f(time_to_be_sleep):
time.sleep(time_to_be_sleep)
print('hello wprld') f(5) if __name__ == '__main__':
unittest.main()

2、都是常规的,有带参数和不带参数的装饰器。其中where_is_it_called装饰器比较复杂一点,只要函数或方法加上这个装饰器,每当函数被别的地方每次调用时候,能记录下它在哪个时候被哪个文件的哪个函数的哪一行代码调用过。这个实在太强了。

由于是本文件中直接测试运行,所以是显示main。

模块 [__main__] 中的方法 [f9] 正在被文件 [D:/Users/xxx/Desktop/oschina/coding/hotel/app/apis/fliggy/utils/decorators.py] 中的方法 [test_where_is_it_called] 中的第 [266] 行处调用

面向切面编程AOP,一些通用装饰器的更多相关文章

  1. Spring框架系列(4) - 深入浅出Spring核心之面向切面编程(AOP)

    在Spring基础 - Spring简单例子引入Spring的核心中向你展示了AOP的基础含义,同时以此发散了一些AOP相关知识点; 本节将在此基础上进一步解读AOP的含义以及AOP的使用方式.@pd ...

  2. [译]如何在ASP.NET Core中实现面向切面编程(AOP)

    原文地址:ASPECT ORIENTED PROGRAMMING USING PROXIES IN ASP.NET CORE 原文作者:ZANID HAYTAM 译文地址:如何在ASP.NET Cor ...

  3. 设计模式之面向切面编程AOP

    动态的将代码切入到指定的方法.指定位置上的编程思想就是面向切面的编程. 代码只有两种,一种是逻辑代码.另一种是非逻辑代码.逻辑代码就是实现功能的核心代码,非逻辑代码就是处理琐碎事务的代码,比如说获取连 ...

  4. Spring学习手札(二)面向切面编程AOP

    AOP理解 Aspect Oriented Program面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. 但是,这种说法有些片面,因为在软件工程中,AOP的价值体现的并 ...

  5. Spring学习笔记:面向切面编程AOP(Aspect Oriented Programming)

    一.面向切面编程AOP 目标:让我们可以“专心做事”,避免繁杂重复的功能编码 原理:将复杂的需求分解出不同方面,将公共功能集中解决 *****所谓面向切面编程,是一种通过预编译方式和运行期动态代理实现 ...

  6. Spring框架学习笔记(2)——面向切面编程AOP

    介绍 概念 面向切面编程AOP与面向对象编程OOP有所不同,AOP不是对OOP的替换,而是对OOP的一种补充,AOP增强了OOP. 假设我们有几个业务代码,都调用了某个方法,按照OOP的思想,我们就会 ...

  7. Spring之控制反转——IoC、面向切面编程——AOP

      控制反转——IoC 提出IoC的目的 为了解决对象之间的耦合度过高的问题,提出了IoC理论,用来实现对象之间的解耦. 什么是IoC IoC是Inversion of Control的缩写,译为控制 ...

  8. 【串线篇】面向切面编程AOP

    面向切面编程AOP 描述:将某段代码“动态”的切入到“指定方法”的“指定位置”进行运行的一种编程方式 (其底层就是Java的动态代理)spring对其做了简化书写 场景: 1).AOP加日志保存到数据 ...

  9. 04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI&&08.面向切面编程 AOP&&10.Spring中事务控制

    spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...

  10. 面向切面编程AOP——加锁、cache、logging、trace、同步等这些较通用的操作,如果都写一个类,则每个用到这些功能的类使用多继承非常难看,AOP就是解决这个问题的,python AOP就是装饰器

    面向切面编程(AOP)是一种编程思想,与OOP并不矛盾,只是它们的关注点相同.面向对象的目的在于抽象和管理,而面向切面的目的在于解耦和复用. 举两个大家都接触过的AOP的例子: 1)java中myba ...

随机推荐

  1. BZOJ4714 : 旋转排列

    对于每个$k$,问题等价于求有多少置换满足: 1.存在一个循环长度为$k$ 2.任意一个循环长度$\geq 2$ 枚举这种环的个数$t$: 设$g_t$表示至少有$kt$个人分成$t$个长度为$k$的 ...

  2. php boolean

    要明确地将一个值转换成 boolean,用 (bool) 或者 (boolean) 来强制转换 var_dump((); // true 当转换为 boolean 时,以下值被认为是 FALSE: 1 ...

  3. phantomjs + python 打造一个微信机器人

    phantomjs + python 打造一个微信机器人 1.前奏   媳妇公司不能上网,但经常需要在公众号上找一些文章做一些参考,需要的时候就把文章链接分享给我,然后我在浏览器打开网页,一点点复制过 ...

  4. C#编程(八十二)---------- 用户自定义异常类

    用户自定义异常类 前面已经说了不少关于异常的问题了,现在来给大家说一下自定义异常时咋个回事以及咋样. 为啥会出现自定义异常类呢?用用脚趾头想想也明白,是为了定义咱们自己的异常,自定义异常类继承自App ...

  5. 【docker】docker部署spring boot服务,但是docker logs查看容器输出控制台日志,没有日志打印,日志未打印,docker logs不打印容器日志

    如题: docker部署spring boot服务,但是docker logs查看容器输出控制台日志,没有日志打印,日志未打印,docker logs不打印容器日志 场景再现: docker部署并启动 ...

  6. JVM Debugger Memory View for IntelliJ IDEA

    Posted on August 19, 2016 by Andrey Cheptsov Every day we try to find new ways to improve developer ...

  7. 使用Let’s Encrypt生成免费的SSL证书

    SSL(安全套接层,Secure Sockets Layer),及其继任者 TLS (传输层安全,Transport Layer Security)是为网络通信提供安全及数据完整性的一种安全协议.TL ...

  8. Spark2.3(三十七):Stream join Stream(res文件每天更新一份)

    kafka测试数据生成: package com.dx.kafka; import java.util.Properties; import java.util.Random; import org. ...

  9. 解决Gerrit的git unpack error问题

    今天上午同事和我说neutron项目要换成全新的内部代码,原先仓库里的代码要全部废弃掉.于是我就简单地创建了一个空项目使用git push --force将其置空. 下午的时候,麻烦事情就来了,同事发 ...

  10. Java 之外,是 Scala 还是 Groovy?【转载】

    原文地址 Scala 和 Groovy 都是基于 JVM 的语言,相比 Java,它们都有语法更加简明和表达能力更丰富.对于那些既想不脱离开 JVM 又想避免 Java 繁琐语句的开发人员来说,Sca ...