python之装饰器


装饰器作用:在不改变原代码的情况下增强原代码的功能

装饰器返回的是可调用的(函数)对象,可调用的(函数)对象,可调用的(函数)对象。

判断函数是否为闭包可通过func的__closure__查看,如里边带__cell__元素,那么可以认为这个函数是闭包.

而__cell__里边包含着函数内部所引用的非全局的变量

不要被@迷惑

@只是一个语法糖

1.
def func1(func):
    print(1)
    
@func1
def func2():
  pass

func2()

2.
def func1(func):
    print(1)

def func2():
    pass

func1(func2)

'''
第一段代码中的func2()和第二段代码中的func1(func2)是等价的
@只是一个语法糖,当使用
@func1
def func2()
  pass

func2 会被重新定义成func1(func2)
相当于
a = 1000
a = a + 1
这是a已经不再是1000了 而是通过a+1得出来的结果1001  而1000早已经被销毁
'''

装饰器的使用:

情景1:实现用户访问某些网页时,需要先登录,如果没登录就重定向到登录界面

def login_required(func):
    def wrapper(*args, *kwargs):
        if 'user is login':
            result = func()
        else:
            print('please login first')
            result = redirect(login_url)
        return result
    return wrapper

@login_required
def func():
    pass

这时每次调用func时 就会先判断用户是否已经登录,然后再执行func函数里边对应的操作

情景2:但是有时候login_url 并不是固定的 所以我们需要在使用时自定义返回的页面

def login_required(login_url='login.html')
    def outer(func):
        def wrapper(*args, *kwargs):
            if 'user is login':
                result = func()
            else:
                print('please login first')
                result = redirect(login_url)
            return result
        return wrapper
    return outer

@login_required(login_url='login2.html')
def func():
    pass

这时候,只需要在最外边再定义一层函数来接收调用装饰器时所传递的参数就可以

这时候的func = login_required(login_url='login2.html')(func)(*args, *kwargs)

同时使用多个装饰器:

def outer1(func):
    def inner1():
        print('inner1 first')
        func()
        print('inner1 second')
    return inner1

def outer2(func):
    def inner2():
        print('inner2 first')
        func()
        print('inner2 second')
    return inner2

def outer3(func):
    def inner3():
        print('inner3 first')
        func()
        print('inner3 second')
    return inner3

@outer1
@outer2
@outer3
def func():
    print('Hello World')

当出现同时多个装饰器时,装饰器会从下往上执行

  1. @outer3 func() = outer3(func) --> 返回inner1
  2. @outer2 outer2(func) = outer2(outer3(func)) --> outer3(func)== func 被传入outer2
  3. @outer1 outer1(func) = outer1(outer2(outer3(func))) --> outer2(outer3(func)) == func 被传入outer1

所以实际执行顺序为

  1. outer1(func): --> print('inner1 first')
  2. outer1(func): --> func() == outer2(outer3(func))
  3. outer2(func): --> print('inner2 first')
  4. outer2(func): --> func() == outer3(func)
  5. outer3(func): --> print('inner3 first')
  6. outer3(func): --> func() == func() (装饰器外定义的)
  7. func(): --> print('Hello World')
  8. outer3(func): --> print('inner3 second')
  9. outer2(func): --> print('inner2 second')
  10. outer1(func): --> print('inner1 second')

用类来做装饰器

实现@X

@X func = X(func) --> init

@X() func = X(func)() --> init call

class DecoClass:
    def __init__(self, func):
        self.func = func
    def __call__(self):
        print('执行func前')
        result = self.func()
        print('执行func后')
        return result

@DecoClass
def func():
    print('Hello World')

实现@DecoClass(args)

class DecoClass:
    def __init__(self, args):
        self.arg = args
    def __call__(self, func):
        def inner(*args, **kwargs):
            print(self.arg)
            print('执行func前')
            result = func(*args, **kwargs)
            print('执行func后')
            return result
        return inner

@DecoClass(1)
def func(*args, **kwargs):
    print('Hello World')

使用类当装饰器时,要注意__init__ 和__call__,需要分清他们分别在什么情况下调用,接受的是又什么参数

@DecoClass(1) 1其实是被__init__接收的 而func则被__call__接收

@DecoClass(1) func = DecoClass(1)(func) DecoClass(1)初始化 返回的是实例 实例() 则调用__call__

实现@DecoClass.deco

class DecoClass:
    #[@classmethod|@staticmethod]
    def deco(func):
        def inner(*args, **kwargs):
            print('执行func前')
            result = func(*args, **kwargs)
            print('执行func后')
            return result
        return inner

@DecoClass.deco
def func():
    print('Hello World')

实现@DecoClass.deco(1)

class DecoClass:
    def deco(arg):
        def outer(func):
            def inner(*args, **kwargs):
                print(arg)
                print('执行func前')
                result = func()
                print('执行func后')
                return result
            return inner
        return deco

@DecoClass.deco(1)
def func():
    print('Hello World')

实现@decoclass

class DecoClass:
    def __call__(self, func):
        def inner(*args, **kwargs):
            print('执行func前')
            result = func(*args, **kwargs)
            print('执行func后')
            return result
        return inner

decoclass = DecoClass()

@decoclass
def func():
    print('Hello World')

实现@decoclass(args)

class DecoClass:
    def __call__(self, *args, **kwargs):
        def outer(func):
            print(args)
            def inner(*args, **kwargs):
                print('执行func前')
                result = func(*args, **kwargs)
                print('执行func后')
                return result
            return inner
        return outer

decoclass = DecoClass()

@decoclass(1)
def func():
    print('Hello World')

实现@decoclass.deco

class DecoClass:
    def deco(self, func):
        def inner(*args, **kwargs):
            print('执行func前')
            result = func(*args, **kwargs)
            print('执行func后')
            return result
        return inner


decoclass = DecoClass()

@decoclass.deco
def func():
    print('Hello World')

实现@decoclass.deco(args)

class DecoClass:
    def deco(self, *args, **kwargs):
        def outer(func):
            print(args)
            def inner(*args, **kwargs):
                print('执行func前')
                result = func(*args, **kwargs)
                print('执行func后')
                return result
            return inner
        return outer


decoclass = DecoClass()

@decoclass.deco(1)
def func():
    print('Hello World')


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM