2.3.3装饰器与语法糖

总目录:https://www.jianshu.com/p/e406a9bc93a9

Python - 子目录:https://www.jianshu.com/p/50b432cb9460

装饰器三前提:作用域、高阶函数,闭包

作用域

 L_E_G_B

a = 10   

def f():

    a=5   

    def inner():

        a = 7

        print(a)

        return 1

7


高阶函数

1.函数名可以作为参数输入

2.也可以作为返回值


闭包

def outer():

    x = 10

    def inner():      #条件1: inner就是内部变量

        print(x)        #条件2:外部环境的一个变量

    return inner     #结论:内部函数inner是一个闭包

f=outer()

f()

10


装饰器

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

现在我们来举一个例子:

假设要写一个银行存款取款的程序,那么主干程序肯定要实现存款功能和取款功能:

def a():

    print("存款中……")

def b():

    print("取款中……")

button=1

if button ==1:

    a()

else:

    b()

但是除了存款功能和取款功能外,需要添加密码验证功能,那么菜鸡程序员肯定会添加一个新的函数:

def a():

    print("存款中……")

def b():

    print("取款中……")

def c():

    print("密码验证中……")

button=1

if button ==1:

    c()

    a()

else:

    c()

    b()

或者:

def a():

    c()

    print("存款中……")

def b():

    c()

    print("取款中……")

def c():

    print("密码验证中……")

button=1

if button ==1:

    a()

else:

    b()

但是这两种写法冗余程度高,都违背了开放封闭原则,这只是两个功能就要每一步都要做出修改,那么上百个功能呢?

那么我们在不改变原函数的情况下进行修改:

def a():

    print("存款中……")

def b():

    print("取款中……")

def c(fun):

    print("密码验证中……")

    fun()

button=1

if button ==1:

    c(a)

else:

    c(b)

这样修改确实没有修改原代码,但是程序逻辑已经改变,如果功能多的话,都要一一修改,可维护性差。

这样,就需要我们使用装饰器了,在不影响原程序,原逻辑,不违背开放封闭原则的情况下:

def c(func):

    def inner():

        print("密码验证中……")

        func()

    return inner


def a():

    print("存款中……")


def b():

    print("取款中……")

button=1

if button ==1:

    a1=c(a)

    a1()

else:

    b1=c(b)

    b1()

这个例子只是在说明装饰器的用途和标准用法。

带参装饰器

现在让我们摆脱这个例子,看一下带参数的装饰器,

def c(func):

    def inner():

        print("woshi")

        func()

    return inner


def my(a):

    print(a)


my1=c(my("xiaobai"))

my1()

运行这个代码,会报错,原因是装饰器的返回值是inner,而my等同于inner。

现在我们修改一下

def c(func):

    def inner(*a,**b):

        print("woshi")

        func(*a,**b)

    return inner


def my(a):

    print(a)

my1=c(my("xiaobai"))

my1()

现在我们来看一下,装饰器中的函数返回值:

def c(func):

    def inner(*a,**b):

        print("woshi")

        func(*a,**b)

    return inner

@c

def my1(a):

    return a

@c

def my2(a):

    print(a)


re1 = my1("111")

re2 = my2("222")

print(re1,re2)

woshi

woshi

222

None None

这是打印的结果,可以看出来两个函数的返回值均为空,是因为,无论被装饰的函数有无返回值,其结果都无返回值,原因其实很简单,因为inner()函数根本就没有返回值。为了实现有返回值的函数被装饰之后仍然有返回值,需要inner函数与被装饰函数的返回值保持一致。

再来简单修改一下:

def c(func):

    def inner(*a,**b):

        print("woshi")

        re3=func(*a,**b)

        return re3

    return inner

@c

def my1(a):

    return a

@c

def my2(a):

    print(a)


re1 = my1("111")

re2 = my2("222")

print(re1,re2)

woshi

woshi

222

111 None

可以看到,有返回值的函数被装饰之后依然有返回值,没有返回值的函数被装饰之后则没有返回值,符合我们想要的结果。


语法糖

上面的@c便是语法糖。

我们来定义一个函数

def my():

    print("123")

然后我们要在123上加一行=和一行*

def a(func):

    def inner():

        print('='*15)

        func()

    return inner

def b(func):

    def inner():

        print('*'*15)

        func()

    return inner

@a

@b

def my():

    print("123")

my()

带参语法糖

但是这样的话,函数a和函数b代码冗余,可以用带参数的语法糖来优化一下:

def a(char):

    def b(func):

        def inner():

            print(char*15)

            func()

        return inner

    return b

@a('=')

@a('*')

def my():

    print("123")

my()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返...
    胡一巴阅读 3,114评论 0 0
  • 写在前面的话 代码中的# > 表示的是输出结果 输入 使用input()函数 用法 注意input函数输出的均是字...
    FlyingLittlePG阅读 8,114评论 0 9
  • http://blog.csdn.net/ablo_zhou/article/details/5471952 Py...
    王江涛_6000阅读 2,720评论 0 1
  • 闭包和装饰器 闭包 定义:在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个...
    一只学不会编程的汪汪阅读 2,720评论 0 0
  • 一,老师问全班同学:“小明有三个儿子,大儿子叫小日,二儿子叫小月,那么他第三个儿子叫什么”?这时王小明突然站起来回...
    金字塔顶阅读 1,885评论 0 2