浅谈python3的装饰器

  • 2018-07-13
  • 0
  • 0

浅谈python3的装饰器

作者信息:

Author : 黄志成(小黄)

博客地址: 博客

首先来简述一下什么是装饰器?

装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.

装饰器也是一种设计模式.它遵守着开放-封闭原则.对于开放封闭原则我在这里用一句话总结:一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的.

先说一个需求吧.需要完成两个函数,一个求和函数另一个求平均值函数.

这个很好实现哇.

def func_sum(*arg):
    return sum(arg)

def func_average(*arg):
    return sum(arg) / len(arg)

print(func_sum(1,2,3,4))
print(func_average(1,2,3,4))

输出结果:

10
2.5

看似没问题,能计算出结果.但是如果传入一个字符串或者其他类型该怎么办呢.

那也很简单,我们改造一下这两个函数

def func_sum(*arg):
    if len(arg) == 0:
        return 0
    for i in arg:
        if not isinstance(i,int):
            return 0
    return sum(arg)

def func_average(*arg):
    if len(arg) == 0:
        return 0
    for i in arg:
        if not isinstance(i,int):
            return 0
    return sum(arg) / len(arg)

print(func_sum(1,2,3,4,'asd'))
print(func_average(1,2,3,4))

在运行下

0
2.5

至少不会报错了.但是问题又来了.我们最开始说了开放-封闭原则.但现在已经完全违背了这个原则.那如何改写才能遵守呢.

在如何改写之前咱再说说闭包。闭包这个概念可能有些涩会难懂

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。

def outer():
    def inner():
        return "inner"
    return inner

wai = outer()

print(wai())

结果打印出 inner。现在我们将那两个函数共同的验证部分复用起来.

实现代码如下:

def func_sum(*arg):
    return sum(arg)

def func_average(*arg):
    return sum(arg) / len(arg)

def validate(func):
    def fn(*arg):
        if len(arg) == 0:
            return 0
        for i in arg:
            if not isinstance(i,int):
                return 0
        return func(*arg)
    return fn

func_sum = validate(func_sum)
func_average = validate(func_average)

print(func_sum(1,2,3,4))
print(func_average(1,2,3,4))

在python中函数也是对象,也可以传递.

这样验证的部分复用就实现了.这就是开发-封闭原则.

继续优化下.使用python提供给我们的语法糖 装饰器

@demo @符号后面跟上函数 就是所谓的装饰器.如果你已经理解了闭包.在看下去就会更加简单.

下面给出装饰器版的复用

def validate(func):
    def fn(*arg):
        if len(arg) == 0:
            return 0
        for i in arg:
            if not isinstance(i,int):
                return 0
        return func(*arg)
    return fn

@validate
def func_sum(*arg):
    return sum(arg)

@validate
def func_average(*arg):
    return sum(arg) / len(arg)



print(func_sum(1,2,3,4,'1'))
print(func_average(1,2,3,4))

如果还没有理解装饰器,在列举一个例子.

计算函数运算的时间

大部分人会使用下面这种写法

import time

def func_a():
    time.sleep(1)


start = time.time()
func_a()
end = time.time()

print(end - start)

最后返回结果

1.003756046295166

用装饰器来编写计算函数运行时间的代码

import time

def func_time(func):
    def fn():
        start = time.time()
        func()
        end = time.time()
        print(end - start)
    return fn



@func_time
def func_a():
    print("i'm func_a")
    time.sleep(1)

func_a()

结果返回:

i'm func_a
1.003925085067749

这篇文章就到此结束了.如果本月有时间的话.会再来一篇细说下装饰器.

又到了愉快的周末!今天写的内容.可能会对初学者有些难懂.看不懂的话请多敲几遍.代码是敲出来的.不是看出来的.

写于 2018年07月13日18:38

评论

还没有任何评论,你来说两句吧