精华内容
下载资源
问答
  • python3 装饰器

    2017-09-13 14:32:56
    python3 装饰器
    def outter(func):
        @functools.inner(func) #这样不影响传入的参数
        def inner(*arg):
            print("请输入密码")
            password = input("password : ")
            if password == 'qwe' :
                func(*arg)
            else :
                print("密码不正确")
        return inner
    @outter
    def success():
        print("登录成功")

    success()
    展开全文
  • Python3 装饰器

    千次阅读 2017-05-04 21:58:21
    Python3 装饰器 装饰器: 本质是函数, 用于装饰其他函数, 附加一些本身所没有的功能

    Python3 装饰器


    本文由 Luzhuo 编写,转发请保留该信息.
    原文: http://blog.csdn.net/Rozol/article/details/71189345


    以下代码以Python3.6.1为例
    Less is more!
    装饰器: 本质是函数, 用于装饰其他函数, 附加一些本身所没有的功能

    #!/usr/bin/env python
    # coding=utf-8
    __author__ = 'Luzhuo'
    __date__ = '2017/5/4'
    # decorator.py 装饰器
    # 装饰器: 本质是函数, 用于装饰其他函数, 附加一些本身所没有的功能
    
    
    # 函数就是变量
    def num():
        print("num")
    
    num()
    num = 1  # 函数就是变量
    # num()  # num的引用被指向1,不能再调用
    
    # ========================================
    
    
    # 高阶函数
    def func_1():
        print("func_1")
    
    
    def func_2(func):  # 接收函数变量
        func()
    
    func_2(func_1)  # => func_1
    
    # ========================================
    
    
    # 闭包
    def func_3(line):
        # 闭包: 用于代码封装 和 复用
        def comp(value):  # 嵌套函数: 函数里再嵌套一个函数
            # 函数set_line执行完(生命周期结束), 自由变量(line)仍存活于包裹内
            if value >= line:
                print("{} >= {}".format(value, line))
            else:
                print("{} < {}".format(value, line))
    
        return comp
    
    f = func_3(60)  # 调用函数A(set_line()),返回函数B(cmp()),这个函数B就叫闭包
    f(89)  # => 89 >= 60
    f(59)  # => 59 < 60
    
    # ========================================
    
    
    # 装饰器, 在不修改my_average()代码的情况下,为其添加了一些功能(wrapper())
    def dec_1(func):
        def wrapper(num1, num2):
    
            # --- 附加功能 ---
            if num2 == 0:
                print("num2 值不能为0")
    
            return func(num1, num2)
        return wrapper
    
    
    # 普通调用方式
    def average_1(num1, num2):
        return num1 / num2
    
    average_1 = dec_1(average_1)
    print(average_1(5, 3))  # => 1.6666666666666667
    
    
    # 使用@语法糖的方式
    @dec_1  # (sum = dec(sum))
    def sum_1(num1, num2):
        return num1 + num2
    
    print(sum_1(5, 3))  # => 8
    
    # ========================================
    
    
    # 能接收任何参数的通用装饰器
    def dec_2(func):
        def wrapper(*arg, **kwargs):
    
            # --- 附加功能 ---
            print("loging i ...")
    
            return func(*arg, **kwargs)
        return wrapper
    
    
    @dec_2
    def average_2(num1, num2):
        return num1 / num2
    
    print(average_2(5, 3))  # => loging i ... => 1.6666666666666667
    
    
    @dec_2
    def sum_2(*args):
        return sum(args)
    
    print(sum_2(5, 3, 2, 1))  # => loging i ... => 11
    
    # ========================================
    
    
    # 能接收不同参数的装饰器
    def auth(auth_type): # 在外面套一层
        def dec_3(func):
            def wrapper(*arg, **kwargs):
                # --- 附加功能 ---
                if auth_type == "admin":
                    print("你是管理员")
                elif auth_type == "user":
                    print("你是普通用户")
                else:
                    print("你是外星人吗?")
    
                return func(*arg, **kwargs)
            return wrapper
        return dec_3
    
    
    # 普通调用方式
    @auth(auth_type="admin")
    def average_3(*arg):
        return sum(arg) / len(arg)
    
    print(average_3(1, 2, 3, 4, 5))  # => 你是管理员 => 3.0
    
    
    @auth(auth_type="user")
    def sum_3(*arg):
        return sum(arg)
    
    print(sum_3(5, 3, 2, 1))  # => 你是普通用户 => 11
    
    
    # ========================================
    
    
    # 使用多个装饰器
    @dec_1
    @dec_2
    @auth(auth_type="admin")
    def average_2(num1, num2):
        return num1 / num2
    
    # 执行顺序dec_1 => dec_2 => auth => average_2
    print(average_2(5, 3))  # => loging i ... => 你是管理员 => 1.6666666666666667
    
    展开全文
  • Python3装饰器

    2018-11-26 10:20:23
    Python中的装饰器是一种可调用的对象(它可以是函数、或类),它将被装饰对象(函数、或类)作为参数传入,再经过执行所需要的处理后,返回另一个可调用对象。 函数装饰器 本节介绍常见的用一个函数装饰器,装饰另一个...

    介绍

    Python中的装饰器是一种可调用的对象(它可以是函数、或实现__call__的类),它将被装饰对象(函数、或类)作为参数传入,再经过执行所需要的处理后,返回另一个可调用对象。装饰器的本质就是把一个可调用对象变成另一个可调用对象。装饰器可以由以下多种用法。

    1. 函数装饰器装饰函数
    2. 函数装饰器装饰类
    3. 函数装饰器装饰方法(类中定义的函数)
    4. 实现__call__的类装饰器装饰函数
    5. 实现__call__的类装饰器装饰类
    6. 实现__call__的类装饰器装饰方法(类中定义的函数)

    函数装饰器

    本节介绍常见的用一个函数装饰器,装饰另一个函数的情况。
    装饰器的功能为修改、加工被装饰函数的功能,为了解装饰器的简单原理,我们一步步描述如何修饰函数对象。

    1. 函数赋值
      Python中函数也是一种对象,它可以赋值给变量。
    def func():
        print("hello func.")
    
    def changed_func():
        print("hello changed func.")
    
    func()
    ## output: hello func.
    func = changed_func
    func()
    ## output: hello changed func.
    

    从上面的代码可以看到,我们可以通过函数赋值给变量的方法,使func可以调用不同的实际函数。

    1. 将函数作为参数
      因为函数亦是对象,因此可以作为函数参数传入。
    def decorate(func):
        return changed_func
    
    def func():
        print("hello func.")
    
    def changed_func():
        print("hello changed func.")
    
    func()
    ## output: hello func.
    func = decorate(func)
    func()
    ## output: hello changed func.
    
    

    我们可以通过将func传到decorate函数中,让decorate函数帮忙返回修改后的函数changed_func,此时func()和第一种直接赋值的方法类似,具备了新的功能,成为了新的函数changed_func。

    1. 装饰器方法
      将上小节中func传入decorate函数赋值的方法,改造成Python的装饰器用法。
    def decorate(func):
        def changed_func(*args, **kwargs):
            print("hello changed func.")
            return func(*args, **kwargs)
    
        return changed_func
    
    
    @decorate
    def func():
        print("hello func.")
    
    
    func()
    
    """ output
    hello changed func.
    hello func.
    """
    
    

    通过Python的语法糖@,可以在func定义时对函数进行修饰,使func变为新的函数,这里将changed_func函数定义到了decorate函数里使装饰器函数更加内聚紧凑,如果像前面两节独立定义changed_func的方式,也不影响功能。
    前面两种修改函数对象的方法都是在程序运行时完成的,而装饰器作为Python的一种语法,就像第2小节decorate赋值的方法: func = decorate(func)一样,对func完成了赋值操作,只不过它是在模块导入的时候就已经完成了这个操作。
    因此@decorate可以理解为func = decorate(func)。装饰器decorate返回的是一个闭包,当调用func()时,相当于调用了changed_func(),关于闭包可以参考Python3中的命名绑定、解析与函数闭包

    装饰器执行的顺序

    我们通过新建一个Python文件”test.py“,分别通过导入模块和运行test.py文件观察装饰器执行顺序。
    test.py文件:

    def decorate(func):
        print("decorate func: %s" % func)
        return func
    
    @decorate
    def func1():
        print("hello func1.")
    
    @decorate
    def func2():
        print("hello func2.")
    
    if __name__ == '__main__':
        func1()
        func2()
    

    当在某一个模块中使用from test import *的导入模块语句时,程序的输出为:

    decorate func: <function func1 at 0x10d44a950>
    decorate func: <function func2 at 0x10e785378>
    

    而直接运行 python3 test.py时程序的输出为:

    decorate func: <function func1 at 0x10aa37840>
    decorate func: <function func2 at 0x10aa37950>
    hello func1.
    hello func2.
    

    可以看到装饰器decorate在模块导入时就已经执行,并将被装饰函数:func1、func2修饰。而在运行的执行func1和func2时,func1和func2已经被装饰器修饰,因此可以理解为装饰器是一种静态修饰函数功能的方法。

    装饰器保留函数元信息

    def decorate(func):
        def changed_func(*args, **kwargs):
            print("hello changed func.")
            return func(*args, **kwargs)
    
        return changed_func
    
    
    @decorate
    def func():
        print("hello func.")
    
    
    print(func.__name__)
    
    """ output
    changed_func
    """
    
    

    我们可以看到,当装饰器decorate装饰了函数func时,func相当于变成了changed_func,因此在打印func.__name__时显示的是函数changed_func的名字。我们可以通过Python标准库中的functools.wraps装饰器,使changed_func函数保留原始函数func的信息。

    from functools import wraps
    
    
    def decorate(func):
        @wraps(func)
        def changed_func(*args, **kwargs):
            print("hello changed func.")
            return func(*args, **kwargs)
    
        return changed_func
    
    
    @decorate
    def func():
        print("hello func.")
    
    
    print(func.__name__)
    func.__wrapped__()
    
    """ output
    func
    hello func.
    """
    

    通过wraps装饰器,func函数拥有了__wrapped__属性,该属性就是不被装饰器修饰的func本身,因此调用该函数只是调用了func函数而没有被装饰器修饰。

    带参数的装饰器

    from functools import wraps
    
    
    def decorate(arg1):
        print(arg1)
    
        def _decorate(func):
            @wraps(func)
            def changed_func(*args, **kwargs):
                print("hello changed func.")
                return func(*args, **kwargs)
    
            return changed_func
    
        return _decorate
    
    
    @decorate("test")
    def func():
        print("hello func.")
    
    
    func()
    
    """ output
    test
    hello changed func.
    hello func.
    """
    

    @decorate('test)相当于func = decorate(‘test’)(func)
    除此之外还有一些函数装饰器的用法不过多介绍,其实只要记住装饰器的本质就可以了,参考以下链接:

    1. 可自定义属性的装饰器
    2. 带可选参数的装饰器
    3. 将装饰器定义为类的一部分

    函数装饰器装饰类和方法

    为类提供装饰器,起到了一些元类的作用,可以重写或修改类的行为,具体可以参考:使用装饰器扩充类的功能
    为方法提供函数装饰器可以参考:为类和静态方法提供装饰器
    它的缺点时不能运用到继承中,下面通过元类的方式简单实现可以继承的装饰器。元类相关信息可以参考:Python3元类

    class DecoratorInheritMeta(type):
        def __new__(metacls, *args, **kwargs):
            _, bases, namespace = args
            need_inherit_map = {k: v for k, v in namespace.items() if hasattr(v, '__wrapper__')}
            for base in bases:
                for k, v in getattr(base, '__need_inherit_map__', {}).items():
                    if k in namespace.keys():
                        namespace[k] = v.__wrapper__(namespace[k])
                    else:
                        need_inherit_map[k] = v
    
            cls = super().__new__(metacls, *args)
            cls.__need_inherit_map__ = need_inherit_map
    
            return cls
    
    
    class DecoratorInheritMetaMixin(metaclass=DecoratorInheritMeta):
    
        @staticmethod
        def inherit_decorator(decorator):
            def decorate(func):
                wrapper = decorator(func)
                wrapper.__wrapper__ = decorator
    
                return wrapper
    
            return decorate
    
    
    def decorate(func):
        def changed_func(*args, **kwargs):
            print("hello changed func.")
            return func(*args, **kwargs)
    
        return changed_func
    
    
    class A(DecoratorInheritMetaMixin):
        @DecoratorInheritMetaMixin.inherit_decorator(decorate)
        def func(self):
            print("hello func A.")
    
    
    class B(A):
        def func(self):
            print('hello func B.')
    
    
    A().func()
    
    B().func()
    
    """ output
    hello changed func.
    hello func A.
    hello changed func.
    hello func B.
    """
    

    实现__call__的类装饰器装饰函数

    除了函数可以作为装饰器,任何实现了__call__方法的类也可以作为装饰器,当类装饰器装饰函数时,该函数则变为装饰器的对象,拥有对象的相关属性和方法。例如:

    from functools import wraps
    
    
    class Decorate():
        def __init__(self, func):
            wraps(func)(self)
            self.func = self.__wrapped__
            self.ncalls = 0
    
        def __call__(self, *args, **kwargs):
            self.ncalls += 1
            return self.func(*args, **kwargs)
    
        def total_calls(self):
            return self.ncalls
    
    
    @Decorate
    def func():
        print("hello func.")
    
    
    func()
    func()
    func()
    
    print('Total call times by func: ', func.total_calls())
    
    """ output
    hello func.
    hello func.
    hello func.
    Total call times by func:  3
    """
    
    

    通过以上代码可以实现计算函数func执行的次数,装饰器类Decorate在装饰func时,生成对象(执行__init__方法),这里调用’wraps(func)(self)’,目的和之前的@wraps(func)一样,保留func的元信息,只不过这里的self相当于之前函数装饰器时的内部函数。通过实现__call__方法,可以把Decorate的对象变为可调用对象,这里执行被装饰函数func以及其他工作。func由于被Decorate修饰,具有Decorate对象的方法,因此可以通过调用func.total_calls方法,实现得到func被调用总次数的功能。通过使用类装饰器的方法,不但可以实现函数装饰器闭包的功能, 还可以更清晰地看到被装饰后拥有哪些属性和方法,可以使装饰器更加灵活。

    装饰器类装饰方法和类

    当装饰器类修饰方法时需要特别注意。按照装饰器的核心,装饰器将被装饰的可执行对象变为装饰器类的对象,而由于函数这个对象存在__get__方法(为了类对象的方法访问,在类中定义的函数本身是个描述器),因此我们也需要为装饰器类实现__get__方法,实现对象方法调用的描述器功能。

    import types
    from functools import wraps
    
    
    class Decorate():
        def __init__(self, func):
            wraps(func)(self)
            self.func = self.__wrapped__
            self.ncalls = 0
    
        def __call__(self, *args, **kwargs):
            self.ncalls += 1
            return self.func(*args, **kwargs)
    
        def __get__(self, instance, owner):
            if instance is None:
                return self
            return types.MethodType(self, instance)
    
        def total_calls(self):
            return self.ncalls
    
    
    class Test:
        @Decorate
        def func(self):
            print("hello func.")
    
    
    t = Test()
    
    t.func()
    t.func()
    t.func()
    
    print('Total call times by func: ', t.func.total_calls())
    
    """ output
    hello func.
    hello func.
    hello func.
    Total call times by func:  3
    """
    
    

    __get__方法实现了描述器的功能,为了使在调用对象t.func()时实现绑定方法的返回,如不实现该函数,则在调用t.func()不会绑定func中的self。

    至于使用装饰器类直接装饰类的场景还没有遇到过,而且当用这种方法时,被装饰的类会变为装饰器类的对象,在继承时会出现问题,因此这种方法暂不考虑。

    展开全文
  • python3装饰器

    2020-06-23 21:49:46
    为什么要使用装饰器呢? 装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展 装饰器的本质:就是一个闭包函数 那么我们先来看一个简单的装饰器:实现计算每个函数的执行时间的功能 import ...

    为什么要使用装饰器呢?

    • 装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
    • 装饰器的本质:就是一个闭包函数

    那么我们先来看一个简单的装饰器:实现计算每个函数的执行时间的功能

    import time 
    def  wrapper(func):
              def inner():
                    start=time.time()
                    func()
                    end=time.time()
                    print(end-start)
              return inner 
          
    def  hahaha():
             time.sleep(1)
             print('aaaaa')
    hahaha=wrapper(hahaha)
    hahaha()    
    

    简单的装饰器

    • 装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
    • 装饰器的本质:就是一个闭包函数
      在这里插入图片描述
      上面的功能有点不简介,不完美,下面就引进了语法糖
    import time
    def wrapper(func):
           def inner():
               start=time.time()
               func()
               end=time.time()
               print(end-start)
           return inner
    @wrapper
    def  kkk():#相当于kkk=wrapper(kkk)
         print('aaaaa')
         kkk()        
    

    装饰器-------语法糖

    import time
    def timer(func):
         def inner(*args,**kwargs):
             start = time.time()
             re = func(*args,**kwargs)
             end=time.time()
             print(end- start)
             return re
         return inner
    
    @timer   #==> func1 = timer(func1)
    def func1(a,b):
         print('in func1')
         print(a,b)
    
    @timer   #==> func1 = timer(func1)
    def func2(a):
        print('in func2 and get a:%s'%(a))
        return 'fun2 over'
    
    func1(1,2)
    print(func2('aaaaaa'))
    

    开放封闭原则

    • 对扩展是开放的
    • 对修改是封闭的

    装饰器的固定结构

    import time
    def wrapper(func):  # 装饰器
        def inner(*args, **kwargs):
            '''函数执行之前的内容扩展'''
            ret = func(*args, **kwargs)
             '''函数执行之前的内容扩展'''
            return ret
        return inner
    
    @wrapper  # =====>aaa=timmer(aaa)
    def aaa():
        time.sleep(1)
        print('fdfgdg')
    aaa()
    

    带参数的装饰器

    带参数的装饰器:就是给装饰器传参
    用处:就是当加了很多装饰器的时候,现在忽然又不想加装饰器了,想把装饰器给去掉了,但是那么多的代码,一个一个的去闲的麻烦,那么,我们可以利用带参数的装饰器去装饰它,这就他就像一个开关一样,要的时候就调用了,不用的时候就去掉了。给装饰器里面传个参数,那么那个语法糖也要带个括号。在语法糖的括号内传参。在这里,我们可以用三层嵌套,弄一个标识为去标识。如下面的代码示例
    1 # 带参数的装饰器:(相当于开关)为了给装饰器传参

     # F=True#为True时就把装饰器给加上了
     F=False#为False时就把装饰器给去掉了
     def outer(flag):
         def wrapper(func):
             def inner(*args,**kwargs):
                 if flag:
                     print('before')
                     ret=func(*args,**kwargs)
                     print('after')
                 else:
                     ret = func(*args, **kwargs)
                 return ret
             return inner
         return wrapper
     
    @outer(F)#@wrapper
    def hahaha():
         print('hahaha')
    
    @outer(F)
    def shuangwaiwai():
        print('shuangwaiwai')
    
    hahaha()
    shuangwaiwai()
    

    多个装饰器装饰一个函数

    def qqqxing(fun):
         def inner(*args,**kwargs):
             print('in qqxing: before')
             ret = fun(*args,**kwargs)
             print('in qqxing: after')
             return ret
         return inner
     
    def pipixia(fun):
         def inner(*args,**kwargs):
             print('in qqxing: before')
             ret = fun(*args,**kwargs)
             print('in qqxing: after')
             return ret
         return inner
    @qqqxing
    @pipixia
    def dapangxie():
        print('饿了吗')
    dapangxie()
    
     '''
    @qqqxing和@pipixia的执行顺序:先执行qqqxing里面的 print('in qqxing: before'),然后跳到了pipixia里面的
            print('in qqxing: before')
            ret = fun(*args,**kwargs)
             print('in qqxing: after'),完了又回到了qqqxing里面的 print('in qqxing: after')。所以就如下面的运行结果截图一样
     '''
    

    结果
    在这里插入图片描述

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,379
精华内容 1,751
关键字:

python3装饰器

python 订阅