Day 05 Decorator

Decorator(装饰器) 是 Python 中很好用的一个东西,只要 @ 一下就可以处理掉很多东西,其实 Decorator(装饰器) 不难理解,而且容易使用所以在 Python 中很常使用到。不过这篇没有要讲太深,只是让你比较容易理解与使用而已。

装饰器-基本使用

那麽这麽好用的东西怎麽使用呢?就让我们自己做一个简单的出来吧!就先来刻个计算程序执行时间的装饰器好了,这样可以更快的了解。首先架构为这样(就一个资料夹里面有个档案而已啦,算不上架构):

decorator_test/
└── test.py

档案内容为:

test.py

from time import time


def time_counter(func):
    def wrapper(*args, **kwargs):  # 习惯上会取名叫 wrapper
        start = time()
        result = func(*args, **kwargs)
        end = time()
        usage_time = (end - start)
        return result, usage_time

    return wrapper


# 不要括号喔
@time_counter
def star_triangle(times):
    step = ""
    for i in range(1, times+1, 2):
        for j in range((times-i)//2):
            step += " "
        for j in range(i):
            step += "*"
        step += "\n"
    return step


res = star_triangle(5000)  # 5000 如果跑太久可以适当的减少它
print("Time: {:>30.24f} second".format(res[1]))

执行後的时间大概会长这样(嗯,我没有让它输出,不然很恐怖)

> Time:     3.177063703536987304687500 second

蛤,这样就一个喔,啊它到底是怎样出现的?

别急,把15行删掉(@time_counter 那行),再把27行改成这样

res = time_counter(star_triangle)(5000)  # 5000 如果跑太久可以适当的减少它

应该会出现类似的结果(秒数不一样很正常)

> Time:     3.209057331085205078125000 second

这样懂了吗?还记的 Day 06 讲过的这些吗?

在 Python 中,Function 的地位和 C++、Java等不同,是属於 "First-class Citizen" (一等公民),故称作 "First-class function" (一级函数)。

什麽是 "First-class Citizen" 呢?跟二等公民又差在哪呢?

最明显的差别是 Python 中的 Function 可以当成参数传递并执行(对啦,我就是只想讲这句而已,其他暂时不太重要)。

Decorator(装饰器) 就是把@下面的 Function 当成参数传递并执行了,大概就是每次呼叫 Function 都会像这样一层一层转换(这边只是方便理解而已):

Step1: res = star_triangle(5000)
Step2: res = time_counter(star_triangle)(5000)
Step3: res = wrapper(5000):
Step4: res get wrapper return

因为 func 这个东西位於 time_counter 的里面,所以同样位於time_counter 里面的 wrapper 不需要把它当参数也可以使用(大概就是台中市民搭公车免费,你住在北区的话,你也可以免费的意思)

装饰器-加入参数

啊如果装饰器想要有参数的话怎麽办,就再加一层变这样

test.py

from time import time


def time_counter(func):
    def wrapper(*args, **kwargs):  # 习惯上会取名叫 wrapper
        start = time()
        result = func(*args, **kwargs)
        end = time()
        usage_time = (end - start)
        return result, usage_time

    return wrapper


def record_now_time(time_format="%Y-%m-%d %H:%M:%S"):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(datetime.now().strftime(time_format) + " - Start function: " + func.__name__)
            # __name__ 可以取得 Function 的名称
            result = func(*args, **kwargs)
            print(datetime.now().strftime(time_format) + " - End function: " + func.__name__)
            return result

        return wrapper

    return decorator


@record_now_time(time_format="%H:%M:%S")
def star_triangle(times):
    step = ""
    for i in range(1, times+1, 2):
        for j in range((times-i)//2):
            step += " "
        for j in range(i):
            step += "*"
        step += "\n"
    return step


res = star_triangle(5000)  # 5000 如果跑太久可以适当的减少它

这样执行的输出会变这样(最後面的print要删掉)

> 22:20:26 - Start function: star_triangle
> 22:20:29 - End function: star_triangle

装饰器-多层

如果想要同时使用多个装饰器怎麽办,就加上去啊,会变成这样:

test.py

from time import time


def time_counter(func):
    def wrapper(*args, **kwargs):  # 习惯上会取名叫 wrapper
        start = time()
        result = func(*args, **kwargs)
        end = time()
        usage_time = (end - start)
        return result, usage_time

    return wrapper


def record_now_time(time_format="%Y-%m-%d %H:%M:%S"):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(datetime.now().strftime(time_format) + " - Start function: " + func.__name__)
            result = func(*args, **kwargs)
            print(datetime.now().strftime(time_format) + " - End function: " + func.__name__)
            return result

        return wrapper

    return decorator


@time_counter
@record_now_time(time_format="%H:%M:%S")
def star_triangle(times):
    step = ""
    for i in range(1, times+1, 2):
        for j in range((times-i)//2):
            step += " "
        for j in range(i):
            step += "*"
        step += "\n"
    return step


res = star_triangle(5000)  # 5000 如果跑太久可以适当的减少它
print("Time: {:>30.24f} second".format(res[1]))

然後它就会一层一层吃上去,类似这样:

Step1: res = star_triangle(5000)
Step2: res = record_now_time(time_format="%H:%M:%S")(star_triangle)(5000)
Step3: res = time_counter()(record_now_time)(time_format="%H:%M:%S")(star_triangle)(5000)
Step4: res = wrapper(5000):
Step5: res get wrapper return

有没有发现到後面越来越长了,写个装饰器更加的简单明了对吧!

参考资料

Python进阶技巧 (3) — 神奇又美好的 Decorator ,嗷呜!

搞懂Python的装饰器

那麽就大概这样,这篇是让你在使用套件时,遇到装饰器不会不知如何使用而已。话说其实不只 Funciton 可以变成装饰器,Class 也可以。不过关於这个问题,我不会在下个文章讲解(这是一个小坑了,真要讲大概又要开几篇来讲,话说都第五天了还没进主题)。

大家掰~掰~


<<:  [面试]了解自己的市场价值,分析面试管道优劣

>>:  [Day5] Create project、app

【Day 3】Git与Github入门

Git与Github关系? 说明 : Github是Git进行版本控制软件的服务平台供应商之一。 G...

Re-architect - StickyNoteView

上一次我们完成了 ContextMenu 的部分,ContextMenu 也有了属於自己的 View...

Day 20: SOLID 设计原则 — ISP (待改进中... )

「一般来说,如果你所依赖的模组包含了超过你所需要的,那就是有害的,这可能导致不必要的重新编译和重新...

CMoney工程师战斗营weekly3

一山还有一山高课程难度有增无减的一周 上周老师说只要学完抽象类别後应该没有更难的东西,谁知道!!这周...

Apple Music vs Spotify 优缺点比较:哪个更好?

我们将从价格、曲库、音质、歌词方面比较 Spotify 和 Apple Music,让你可以一次了解...