Python Decorator

1 minute read

Published:

0x01 Motivation

装饰函数,增强函数功能,抽象各类函数共同要运行的一些功能,避免重复编写。原理在于Python中函数是一等公民,函数也是对象。

Using Scene

计算程序运算时间,Flask中检验用户是否登录,例如利用装饰器计算函数时间

import time
def time_calc(func):
    def wrapper(*args,**kargs):
        start_time=time.time()
        f=func(*args,**kargs)
        exec_time=time.time()-start_time
        return f
    return wrapper

@time_calc
def add(a,b):
    return a+b
@time_calc
def sub(a,b):
    return a-b

Syntax Forms

# Define a decorator without @ sign
func=decorator(func_name)
func=(decorator(args))(func_time)

# Use @ sign without parameter
@decorator
def func():
    pass

# Use @ sign with parameter
@decorator(args)
def func():
	pass

# Use the decorated function directly
func()

为装饰器传入参数时,装饰器写法(三层函数定义装饰器)

def login(text):
	def decorator(func):
		def wrapper(*args,**kargs):
			print(text)
		return func(*args,**kargs)
	return decorator

@login('args of decorator is added')
def f():
    print('basic func')

Builtin Decorators

@property

用于定义gettersetter相关对,使class中的函数可以被当作类的一个attibuter来使用,使用时可以获取函数返回值。

class Geek:
    _name = 'Sitong'

    @property
    def name(self):
        print("Getter Called")
        return self._name
    
    @name.setter
    def name(self,name):
        print("Setter Called")
        self._name = name

p = Geek()
print(p.name)

p.name = 'Sitong'
print(p.name)

@staticmethod

用于定义类中的static method,不需要传入selfcls参数,可以直接使用。在不需要用到与类相关的属性和方法时,就可以用静态方法。

The @staticmethod decorator is used to indicate that this is a static method. Unlike class methods, static methods do not have a special first parameter that refers to the class itself. Static methods are often used for utility functions that do not depend on the class or the instance of the class.

@classmethod

用于定义class method,不与任何instance绑定,而与class本身绑定。所以不需要传入self参数,但是第一个参数设置为cls

可以用于与class相关的属性或方法,但这些方法是整个类通用的,而不是对象特异的

The @classmethod decorator is used to indicate that this is a class method. The cls parameter in the method definition refers to the class itself, through which the class-level variables (example: class_val) and methods can be accessed.

Using wraps to recover attribute of wrapped function

在使用wrapper函数编写装饰器后,被包装后的函数所有的__doc____name__等属性会被wrapper函数的__doc____name__覆盖,而原有函数的属性则无法被访问。

而编写装饰器时,对wrapper函数使用wraps装饰器即可恢复原有函数的属性,例如:

from functools import wraps

def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """doc of wrapper"""
        print('123')
        return func(*args, **kwargs)

    return wrapper

@decorator
def say_hello():
    """doc of say hello"""
    print('Hi, mates')

# Output "say_hello"
print(say_hello.__name__)

# Output "doc of say hello"
print(say_hello.__doc__)

Reference