ZhangZhihui's Blog  

A decorator is a callable that takes a callable as input and returns a callable. This is the general definition of a decorator. The callable in this definition can be a function or a class. In our initial discussion, we will talk about decorator functions that are used to decorate functions; we will talk about classes later on. So, for the time being, we can think of a decorator as a function that takes a function as input and returns a function.

Decorators are used to add some functionality to a function. They allow you to execute some extra code before or after the execution of a function. This extra work is done without making any changes to the source code of the function. So, by using a decorator we can extend the behavior of a function without actually modifying its code.

A decorator is a function that takes another function as an argument, decorates it with the extra functionality and gives you a decorated function as the result.

复制代码
def func1():
    print('Hello world')
    print('Welcome to Python')

def my_decorator(fn):
    def wrapper():
        print('Hi … Starting execution')
        fn()
        print('Bye … finished executing\n')
    return wrapper

decorated_func1 = my_decorator(func1)
复制代码

 

@my_decorator
def func3():
   print('Learning decorators')

The function func3 is decorated using the automated decoration syntax and so now we do not need to write the statement func3 = my_decorator(func3). The @ syntax automates this reassignment of the function name.

 

Decorator Example: Checking return values

Decorator Example: Checking argument values

 

Preserving metadata of a function after decoration

If we do not want the original function to lose its name, documentation and other attributes, even after decoration, then we can use the wraps function from the functools module. This wraps function is a decorator that copies the introspection details of a function to another function. We will apply this decorator to the wrapper function.

复制代码
from functools import wraps

def trace(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        print(f'{fn.__name__} called')
        print(f'args : {args}  kwargs : {kwargs}' )
        result = fn(*args, **kwargs)
        print(f'Return value : {result}\n')      
        return result

    return wrapper
复制代码

This wraps decorator is little different, it is a decorator that takes an argument. We will see such decorators in the next section. We send function fn as argument to this wrapper function. So now all the important metadata of fn will be copied in the wrapper function.

 

General template for writing a decorator

复制代码
from functools import wraps

def decorator_name(fn):
     @wraps(fn)
     def wrapper(*args, **kwargs):
        #Place code that has to be executed before function call 
        result = fn(*args, **kwargs)
        #Place code that has to be executed after function call 
        return result

     return wrapper
复制代码

 

General template for writing a decorator factory

复制代码
from functools import wraps

def decorator_name(parameter1, parameter2, …):
   def actual_decorator(fn):
     @wraps(fn)
     def wrapper(*args, **kwargs):
        #Place code that has to be executed before function call 
        result = fn(*args, **kwargs)
        #Place code that has to be executed after function call 
        return result

      return wrapper

   return actual_decorator
复制代码

 

Applying decorators to imported functions

We can even apply our own decorators to the functions that we import from standard library or third-party packages. However, we cannot use the @ syntax for these functions.

复制代码
from math import factorial
from random import randint


def trace(fn):
    def wrapper(*args, **kwargs):
        print(f'{fn.__name__} called')
        print(f'args : {args}  kwargs : {kwargs}' )
        result = fn(*args, **kwargs)
        print(f'Return value : {result}\n')      

        return result

    return wrapper


factorial = trace(factorial)
randint = trace(randint)
factorial(3)
randint(5, 50)
复制代码

 

posted on   ZhangZhihuiAAA  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
历史上的今天:
2023-07-31 Go - go.work, go.mod, go.sum
2023-07-31 Go - installation
2023-07-31 Go - env
2023-07-31 Python - match case
 
点击右上角即可分享
微信分享提示