装饰器

标题作用域

标题函数即对象:

在python世界里,函数和我们之前的[1,2,3],‘abc’,8等一样都是对象,而且函数是最高级的对象(对象例化,
可以调用相应的方法,函数是包括变量对象的对象)。

在这里插入代码片
def foo():
    print('i am the foo')
    bar()

def ber():
    print('i am the bar')

foo()
def bar():    #报错
print('i am the bar')

带着这个问题,我们聊聊函数在内存的储存情况:
在这里插入图片描述
函数对象的调用仅仅比其他对象多了一个()而已!foo,bar与a,b一样都是个变量名。
那上面的问题也解决了,只有函数加载到内存才可以被调用。

1.作用域: L_E_G_B

在这里插入代码片X=10
def f():
    a=5
    def inner():
        a=7
        print a
        peturn 1

2.高阶函数
1.函数名可以作为参数输入
2.函数名可以做为反回值

3.闭包 :

在这里插入代码片def outer():
    x=10
    def inner():# 条件一 inner 就是内部函数
        print(x)# 条件2 外部环境的一个变量

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

outer()()
f=outer()
f()
inner() # 局部变量,全局无法调用


f=outer()
f()
def inner():
    print(x)




import time

start=time.time()

time.sleep(1)
end=time.time()

print(end-start)# 1.0011885166168213

print(start) # 1574173303.6451259

遵守开放封闭原则

在这里插入代码片def foo():
    print('foo....')
    time.slepp(2)


def bar():
    print('bar.....') 
    time.sleep(3)


def show_time(f):
    start = time.time()
    f()
    end = time.time()
    print('spend %s' % (end - start))


foo()

show_time(foo)

foo=show_time(foo)

foo()

  1. 其可以被赋给其他变量:
在这里插入代码片def foo():
    print('foo')
bar=foo
bar()
foo()
print(id(foo),id(bar))  #4321123592 432112392

2.其可以被定义在另外一个函数内(作为参数&作为返回值),类似于整形,字符串等对象。

在这里插入代码片#**********函数名作为参数************
def foo(func):
    print('foo')
    func()

def bar():
    print('bar')

foo('bar')

# **********函数名作为返回值*********

def foo():
    print('foo')
    return bar

def bar():
    print('bar')

b=foo()
b()


标题函数的嵌套以及闭包:

抛一个小问题:

在这里插入代码片def foo():
    print('foo')
    def bar():
        print('bar')
    
    # bar()
bar()

bar就是一个变量名,有自己的作用域的。
prthon允许创建嵌套函数。通过在函数内部der的关键字在声明一个函数即为嵌套:

在这里插入代码片# 想执行inner函数,两种方法
def outer():
    x = 1
    def inner():
        print (x) # 1
    # inner()  # 2
    return inner
# outer()
in_func=outer()
in_func()

定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的
变量进行引用,那么内部函数就被认为是闭包(closure).

标题装饰器概念:

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

业务生产中大量调用的函数:

在这里插入代码片def foo():
    print('hell foo')
foo()

现在有一个新的需求,希望可以记录下函数执行时间,于是在代码中添加日志代码:

在这里插入代码片import time
def foo():
    start_time=time.time()
    print('hello foo')
    time.sleep(3)
    end_time=time.time()
    print('spend %s'%(end_time-start-time))

foo()

bar()、bar2()也有类似的需求,怎么做?在bar函数里调用时间函数?这样就造成大量雷同的代码,
为了减少重复写代码,我们可以这样做,重定义一个函数,专门设定时间:

在这里插入代码片import time
def show_time(func):
    start_time=time.time()
    fun()
    end_time=time.time()
    print('spend %s'%(end_time-start_time))

def foo():
    print('hello foo')
    time.slepp(3)

show_time(foo)

标题简单装饰器:

if foo()==show_time(foo) :问题解决!

所以,我们需要show_time(foo)返回一个函数对象,
而这个函数对象内则是核心业务函数:执行func()与装饰函数时间计算,修改如下:

在这里插入代码片import time
 
def show_time(func):
    def wrapper():
        start_time=time.time()
        func()
        end_time=time.time()
        print('spend %s'%(end_time-start_time))
 
    return wrapper
 
 
def foo():
    print('hello foo')
    time.sleep(3)
 
foo=show_time(foo)
foo()


函数show_time就是装饰器,它把真正的业务方法func包裹在函数里面,看起来像foo被上下时间函数装饰了。
在这个例子中,函数进入和退出时,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Peogramming).

@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作:

在这里插入代码片import time

def show_time(func):
    def wrapper():

        start_time=time.time()
        func()
        end_time=time.time()
        print('spend %s'%(end_time-start_time))

    return wrapper

@show_time    # foo=show_time(foo)
def foo():
    print('hello foo')
    time.sleep(3)


@show_time   # bar=show_time(bar)
def bar():
    print('in the bar')
    time.sleep(2)

foo()
print('**********')
bar()

如上所示,这样我们就可以省去bar = show_time(bar)这一句了,直接调用bar()即可得到想要的结果。如果我们有其他的类似函数,
我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。

这里需要注意的问题: foo=show_time(foo)其实是把wrapper引用的对象引用给了foo,而wrapper里的变量func之所以可以用,就是因为wrapper是一个闭包函数。
key:

在这里插入图片描述

@show_time帮我们做的事情就是当我们执行业务逻辑foo()时,执行的代码由粉框部分转到蓝框部分,仅此而已!

装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值