当前位置: 首页 > 科技观察

五个非常方便的Python装饰器,用于分析和调试Python代码

时间:2023-03-13 01:18:26 科技观察

装饰器的美妙之处在于它们非常易于应用,并为您的代码提供了许多额外的功能。在本文中,我将介绍5个方便的装饰器,您可以轻松地将它们应用于调试代码时遇到的实际问题。本文的目的是为您提供一些现成的装饰器,并激发您想出一些方便的通用装饰器。在我们开始之前:您知道您还可以让装饰器跟踪状态吗?示例:计算一个函数被调用的次数,以便您可以对其进行速率限制。请务必阅读:了解装饰器的工作原理、如何应用它们以及何时使用它们。在本文中,我将通过以下5个装饰器来探索装饰器。计时你的函数性能检查中继器询问你确定你确定在执行之前将你的函数包装在一个try-catch中1,计时器让我们从简单开始;我们将从一个装饰器开始,它打印出函数运行所花费的时间。下面是代码:fromfunctoolsimportwrapsimporttimedeftimer(func):@wraps(func)defwrapper(*args,**kwargs):start=time.perf_counter()#Calltheactualfunctionres=func(*args,**kwargs)duration=time.perf_counter()-startprint(f'[{wrapper.__name__}]take{duration*1000}ms')returnresreturnwrapper请注意,我们的包装器本身是用@wraps(func)编写的包裹。这是为了确保我们传递我们的包装函数。如果我们不做wrapper.__name__,只会打印'wrapper'而不是我们实际装饰的函数。我将在计算素数的函数上使用这个包装器:fromfunctoolsimportwrapsimporttimedeftimer(func):@wraps(func)defwrapper(*args,**kwargs):start=time.perf_counter()#调用实际函数res=func(*args,**kwargs)duration=time.perf_counter()-startprint(f'[{wrapper.__name__}]take{duration*1000}ms')returnresreturnwrapper@timerdefisprime(number:int):"""检查一个数是否是素数"""isprime=Falseforiinrange(2,number):if((number%i)==0):isprime=Truebreakreturnisprimeif__name__=="__main__":isprime(number=155153)现在我们调用该函数以查看输出:2.性能检查计时我们的函数很有用,但我们需要更多信息。除了持续时间之外,以下装饰器还提供有关函数的信息,包括其名称和文档字符串,以及内存使用等性能信息:fromfunctoolsimportwrapsimporttimedefperformance_check(func):"""Measureperformanceofafunction"""@wraps(func)defwrapper(*args,**kwargs):tracemalloc.start()start_time=time.perf_counter()res=func(*args,**kwargs)duration=time.perf_counter()-start_timecurrent,peak=tracemalloc.get_traced_memory()tracemalloc.stop()print(f"\n函数:{func.__name__}({func.__doc__})"f"\n内存使用:{current/10**6:.6f}MB"f"\n内存使用峰值:{peak/10**6:.6f}MB"f"\n持续时间:{duration:.6f}sec"f"\n{'-'*40}")returnresreturnwrapper在计算质数的函数上我们仍然使用这个装饰器:kwargs):tracemalloc.start()start_time=time.perf_counter()res=func(*args,**kwargs)duration=time.perf_counter()-start_timecurrent,peak=tracemalloc.get_traced_memory()tracemalloc.stop()print(f"\n函数:{func.__name__}({func.__doc__})"f"\n内存使用:{current/10**6:.6f}MB"f"\n内存使用峰值:{peak/10**6:.6f}MB"f"\nDuration:{duration:.6f}sec"f"\n{'-'*40}")returnresreturnwrapper@performance_checkdefisprime(number:int):"""检查一个数是否是素数"""isprime=Falseforiinrange(2,number):if((number%i)==0):isprime=Truebreakreturnisprimeif__name__=="__main__":a=isprime(number=155153)print(a)让我们调用素数函数看看输出:3.Repeater这个装饰器在调用时重复一个函数这对于测试性能或压力测试很方便,例如defrepeater(iterations:int=1):"""重复装饰函数[iterations]次"""defouter_wrapper(func):defwrapper(*args,**kwargs):res=Noneforiinrange(iterations):res=func(*args,**kwargs)returnresreturnwrapperreturnouter_wrapper让我们使用一个打印hello的函数来测试并让它执行两次。defrepeater(iterations:int=1):"""重复装饰函数[iterations]次"""defouter_wrapper(func):defwrapper(*args,**kwargs):res=Noneforiinrange(iterations):res=func(*args,**kwargs)returnresreturnwrapperreturnouter_wrapper@repeater(iteratinotallow=2)defsayhello():print("hello")现在调用sayhello()将产生以下输出,这个装饰器适用于多个执行,例如测量函数的性能。4.执行函数前提示你是否继续执行这个装饰器可以加在需要很长时间才能完成或者有重大后果(比如删除数据)的函数中。一旦你调用了这个函数,装饰器将确保你在调用它之前确认你想要执行这个函数。否则它只是返回而不调用函数。defprompt_sure(prompt_text:str):"""显示询问您是否要继续的提示。退出除了y(es)"""defouter_wrapper(func):defwrapper(*args,**kwargs):if(input(prompt_text).lower()!='y'):returnreturnfunc(*args,**kwargs)returnwrapperreturnouter_wrapper我们还是用sayhello函数来演示装饰器的功能defprompt_sure(prompt_text:str):"""显示询问您是否要继续的提示。退出除了y(es)"""defouter_wrapper(func):defwrapper(*args,**kwargs):if(input(prompt_text).lower()!='y'):returnreturnfunc(*args,**kwargs)returnwrapperreturnouter_wrapper@prompt_sure('确定吗?按y继续,按n停止。')defsayhello():print("hi")if__name__=="__main__":sayhello()我们可以在装饰器上设置提示消息。当我们调用sayhello()时,我们会看到Sure?按y继续,按n停止。如果我们输入'y'然后我们将执行sayhello(),任何其他输入(包括没有输入将阻止sayhello()执行)。5.装饰器中的TryCatch这使用装饰器将您的函数包装在try-except-block中。优点是只需一行Python代码,您的整个函数就不会出现异常。代码如下所示:deftrycatch(func):"""在try-catch中包装装饰函数。如果函数失败,则打印出异常。"""@wraps(func)defwrapper(*args,**kwargs):try:res=func(*args,**kwargs)returnresexceptExceptionase:print(f"Exceptionin{func.__name__}:{e}")returnwrapper我们将在以下函数中使用它Decoratordeftrycatch(func):"""在try-catch中包装装饰函数。如果函数失败打印出异常。"""@wraps(func)defwrapper(*args,**kwargs):try:res=func(*args,**kwargs)returnresexceptExceptionase:print(f"Exceptionin{func.__name__}:{e}")returnwrapper@trycatchdeftrycatchExample(numA:float,numB:float):返回numA/numBif__name__=="__main__":trycatchExample(9.3)trycatchExample(9,0)现在,当我们调用trycatchExample(9,3)函数时,它返回3.0。如果我们调用trycatchExample(9,0)(除以0),它会在trycatchExample中正确返回以下异常:除以零我建议仅将此装饰器用于调试代码并更准确地捕获函数中的错误。结论通过这篇文章,我希望提供更多关于装饰器带来的优势的信息。如果我启发了你,请分享一些你自己的得心应手的装饰器。本文转载自微信公众号“书阁会编程”,可通过以下二维码关注。转载本文请联系书哥汇编程公众号。