zoukankan      html  css  js  c++  java
  • python--装饰器

    python装饰器学了几篇,比较难理解,特写此博客分析装饰器原理和实例:

    一、装饰器概念

    python装饰器就是用于拓展被装饰函数功能的一种函数(一般是高阶函数,接受被装饰器函数当做参数传入),这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改被装饰函数的代码前提下给函数增加新的功能。

    二、实例

    需求1: 统计函数的执行时间

    1. 不是装饰器的装饰器

    import time

    def decorator(fun):
    start = time.time()
    fun()
    runtime = time.time()-start
    print(runtime)

    def do_something():
    for i in range(1000000):
    pass
    print("play game")

    decorator(do_something)

    结果如下:

    play game
    0.024060487747192383

    这种实现看上去还可以,但是每次调用的是decorator,还要把函数作为一个参数传入。这样需要修改调用的地方,使用起来就不方便了。

    2. 最简单的装饰器

    import time

    def decorator(fun):
    def wrapper():
    start = time.time()
    fun()
    runtime = time.time()-start
    print(runtime)
    return wrapper

    @decorator
    def do_something():
    for i in range(1000000):
    pass
    print("play game")
    do_something()

    结果如下:

    play game
    0.023060321807861328

    装饰器是在函数定义时前面加@,然后跟装饰器的实现函数。可以看出,现在只要直接调用do_something就可以了。调用的地方不要作任何修改。

    3. 目标函数带固定参数的装饰器

    import time

    def decorator(fun):
    def wrapper(name):
    start = time.time()
    fun(name)
    runtime = time.time()-start
    print(runtime)
    return wrapper

    @decorator
    def do_something(name):
    for i in range(1000000):
    pass
    print("play game " + name)

    do_something("hahaha")

    结果如下:

    play game hahaha
    0.024062395095825195

    实现很简单, 就是给wrapper函数参加相同的参数

    4. 目标函数带不固定参数的装饰器

    import time

    def decorator(fun):
    def wrapper(*args, **kwargs):
    start = time.time()
    fun(*args, **kwargs)
    runtime = time.time()-start
    print(runtime)
    return wrapper

    @decorator
    def do_something(name):
    for i in range(1000000):
    pass
    print("play game " + name)

    @decorator
    def do_something2(user, name):
    for i in range(1000000):
    pass
    print(user+" play game " + name)

    do_something("hahaha")
    do_something2("gebilaowang", "hahaha")

    结果如下:

    play game hahaha
    0.0240633487701416
    gebilaowang play game hahaha
    0.02406454086303711

    需求2: 目标函数每次调用重复执行指定的次数

    5. 让装饰器带参数

    import time

    def decorator(max):
    def _decorator(fun):
    def wrapper(*args, **kwargs):
    start = time.time()
    for i in range(max):
    fun(*args, **kwargs)
    runtime = time.time()-start
    print(runtime)
    return wrapper
    return _decorator

    @decorator(3)
    def do_something(name):
    for i in range(1000000):
    pass
    print("play game " + name)

    结果如下:

    play game hahaha
    play game hahaha
    play game hahaha
    0.07122611999511719

    三. 原理

    1 不带参数的装饰器

    @a_decorator

    def f(...):

    ...

    #经过a_decorator后, 函数f就相当于以f为参数调用a_decorator返回结果。 f = a_decorator(f)

    来分析上面的装饰器, 可以看出至少要满足以下几个条件 
    1. 装饰器函数运行在函数定义的时候 
    2. 装饰器需要返回一个可执行的对象 
    3. 装饰器返回的可执行对象要兼容函数f的参数

    2 验证分析

    1 装饰器运行时间

    import time

    def decorator(fun):
    print("decorator")

    def wrapper():
    print("wrapper")
    start = time.time()
    fun()
    runtime = time.time()-start
    print(runtime)
    return wrapper

    @decorator
    def do_something():
    for i in range(1000000):
    pass
    print("play game")
    结果如下:
    decorator
    可以看出, 这里的do_something并没有调用, 但是却打印了decorator, 可wrapper没有打印出来。也就是说decorator是在do_something调用之前的时候执行的。

    2 返回可执行的对象

    import time
    def decorator(fun):
    print("decorator")
    def wrapper():
    print("wrapper")
    start = time.time()
    fun()
    runtime = time.time()-start
    print(runtime)
    return None
    @decorator
    def do_something():
    for i in range(1000000):
    pass
    print("play game")

    do_something()
    结果如下:

    File "C:/Users/xudachen/PycharmProjects/Python全栈开发/第二模块/导师考核/test.py", line 18, in <module>
    do_something()
    TypeError: 'NoneType' object is not callable

    3 兼容函数f的参数

    import time
    def decorator(fun):
    print("decorator")
    def wrapper():
    print("wrapper")
    start = time.time()
    fun()
    runtime = time.time()-start
    print(runtime)
    return wrapper
    @decorator
    def do_something(name):
    for i in range(1000000):
    pass
    print("play game")

    do_something("hahaha")

    结果如下:

    Traceback (most recent call last):
    File "C:/Users/xudachen/PycharmProjects/Python全栈开发/第二模块/导师考核/test.py", line 19, in <module>
    do_something("hahaha")
    TypeError: wrapper() takes 0 positional arguments but 1 was given

    3 带参数的装饰器

    @decomaker(argA, argB, ...)

    def func(arg1, arg2, ...):

    pass

    #这个式子相当于 func = decomaker(argA, argB, ...)(func)

    先写到这里

    参考博客:

    http://blog.csdn.net/TangHuanan/article/details/45094497

  • 相关阅读:
    shutil文件去重模块
    Nexus构建npm、yum、maven私有仓库
    centos7添加自定义服务到systemctl
    Sonatype nuxus私有仓库介绍
    rancher单节点备份和恢复
    rancher证书过期X509:certificate has expired or is not ye valid
    清理docker日志
    mysql 9 hash索引和B+tree索引的区别
    mysql 8 索引
    mysql 7 慢查询+慢查询工具
  • 原文地址:https://www.cnblogs.com/xudachen/p/8556218.html
Copyright © 2011-2022 走看看