python装饰器

先理解闭包函数

闭包:如果在一个函数的内部定义了另一个函数,外部的函数叫他外函数,内部的函数叫他内函数。

  • 在一个函数中定义了一个内函数
  • 内函数里运用了外函数的临时变量
  • 外函数的返回值是内函数
# 外函数
def outer(a):
    # 内函数
    def inner(b):
        # 引用外函数的变量a
        return a + b
    # 将内函数返回
    return inner

if __name__ == '__main__':
    # 传入a,实例化外函数,因a被被函数使用,地址存在内存中供inner函数使用
    out = outer(1)
    # 打印结果:<function outer.<locals>.inner at 0x0000029E27ED4F28>
    print(out)
    # 传入b,输出return a + b, 打印结果:3
    print(out(2))

装饰器:Decorator

又称语法糖,用于扩展函数的功能

闭包写法

def added(func):
    def wrapper(*args, **kwargs):
        func(*args, **kwargs)
        print("执行了内函数")
    print("执行了外函数")
    return wrapper

def add(x, y):
    print(x+y)

adds = added(add)
adds(1, 2)

# 运行结果
--> 执行了外函数
--> 3
--> 执行了内函数

装饰器写法

def added(func):
    def wrapper(*args, **kwargs):
        func(*args, **kwargs)
        print("执行了内函数")
    print("执行了外函数")
    return wrapper

@added
def add(x, y):
    print(x+y)

add(1, 2)

# 运行结果
--> 执行了外函数
--> 3
--> 执行了内函数

优点:简化代码,易维护,增加可读性,@added = adds = added(add)

带参数的装饰器

def info(value):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(value)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@info(value='这是装饰器参数')
def say():
    print('hello')

say()

补充:python函数加括号和不加括号的区别

  1. 不带括号时,调用的是函数本身
  2. 带括号(此时必须传入需要的参数),调用的是函数的return结果

python内置装饰器

  • @property
  • @staticmethod
  • @classmethod

共同点:作用在类的方法上

property 装饰器

用于类中的函数,我们可以像访问属性一样来获取一个函数的返回值

class Date:
    year = "2021"
    month = "10"
    day = "01"

    @property
    def full_date(self):
        return self.year + "-" + self.month + "-" + self.day


date = Date()
print(date.full_date)

staticmethod 装饰器

1、用于类中的函数,表示这个方法将会是一个静态方法
2、该方法无需实例化,可以直接被调用
3、该函数无需 self 参数

class Person:
    @staticmethod
    def say():
        print('hello')

Person.say()

classmethod 装饰器

1、表示这个方法是一个类方法,该方法可以直接被调用无需实例化,
2、没有 self 参数,也无法访问实例化后的对象。
3、相对于 staticmethod 的区别在于它会接收一个指向类本身的 cls 参数。

class Person:
    name = '朋友'
    @classmethod
    def say(cls):
        print('hello:' + cls.name)

Person.say()

类装饰器

当我们调用一个对象时,实际上调用的是它的 __call__ 方法。

class Person:
    def __call__(self):
        print('我是 Person')

person = Person()
person()

使用

class Decorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print('执行了__call__方法')
        return self.func(*args, **kwargs)

@Decorator
def say():
    print('hello')

say()

同一个函数使用多个装饰器

def updatex(func):
    def wrapper(x,y):
        x += 1
        return func(x,y)
    print("x增加了1")
    return wrapper

def updatey(func):
    def wrapper(x,y):
        x += 1
        y += 5
        return func(x,y)

    print("y增加了5")
    return wrapper


@updatex
@updatey
def add(x, y):
    print(x+y)

add(1,1)

# 输出结果
--> y增加了5
--> x增加了1
--> 9

测试例子

1、计算耗时

import time

def cons(func):
    def wrapper():
        start_time = time.time()
        func()
        end_time = time.time()
        cons_time = end_time - start_time
        print("=========")
        print(f"总耗时:{int(cons_time)}秒")
    return wrapper

@cons
def loop():
    i = 0
    while True:
        i += 1
        if i > 500000:
            break
        print(i)

loop()

2、区分登录用户

from functools import wraps

def decorator(func):
    # 指向原函数func的__name__
    @wraps(func)
    def wrapper():
        if func.__name__ == "userA":
            func()
        else:
            print("请先登录!")

    return wrapper

@decorator
def userA():
    print(f"{userA.__name__}  登录成功")

@decorator
def userB():
    print(f"{userB.__name__}  登录成功")


userA()
userB()
posted @ 2021-10-30 17:10  菜鸟志  阅读(52)  评论(0)    收藏  举报