day4-装饰器前奏

定义

装饰器:本质是函数

功能:装饰其他函数,就是为其他函数添加附加功能

原则

1.不能修改被装饰的函数的源代码

2.不能修改被装饰函数的调用方式

def logging():
    print("logging...")
 
#正确写法,没有修改源码
def test1():
    pass
 
#错误写法,不能修改源码
def test1():
    pass
    logging()
 
# 调用方式,也不能被修改
test1()

实现装饰器的知识储备

1.函数即"变量"

2.高阶函数

3.嵌套函数

高阶函数+嵌套函数=》装饰器

1.函数即"变量

(1).python的内存机制

#变量
x = 1
#函数
def test():
    pass
以上一个变量一个函数在内存中的表现形式如下图:
在python解释器中,有一个概念叫做引用基数,那什么叫引用基数呐,就是比方说,x=1,它会先在内存当中把1这个值试试在在的存放下来,这个x其实就是1的门牌号,也是对1的一次引用。python什么时候把这个1这个屋子清空呐?它会等到1所对应的门牌号都没有了,就会把1这里面的东西给清掉,这个也是python的内存回收机制,就是靠这种方式回收的。

(2).del清理

那我们用什么清理呐?用del去清理门牌号,就是对1的值引用的变量,del  x就表示清理掉1对应的x的门派号。如果x没有被del,则x永远不还被删除,除非程序结束了,不然永远不会被删除。del删除的不是1,只是把门牌号x删除了,只是定期刷新时,发现1没有被其他门牌号引用了,才会被清掉。

(3).函数在内存的表现形式

我们先通过四个例子来解释一下:

1) bar函数在foo函数之前定义

def bar():
     print("in the bar")

def foo():
      print("in the foo")
      bar()
foo()
#输出
in the foo
in the bar 

2) bar函数在foo函数之后定义

def foo():
     print("in the foo")
     bar()

def bar():
     print("in the bar")

foo()
#输出
in the foo
in the bar  
# 函数即"变量",bar()有对应的房间(函数体),python执行是按照解释器一行行解释,将函数体放入内存,只要函数体在内存中存在,才可以进行调用

3) bar函数在foo函数调用之后声明

def foo():
     print("in the foo")
     bar()

foo()

def bar():
      print("in the bar")
#输出
in the foo
NameError: name 'bar' is not defined 
# 函数即"变量",在foo()执行前,bar()没有对应的房间(函数体),所以不能被调用

2.高阶函数

实现高阶函数的两个必要条件

a.把一个函数名当做实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)

b.返回值中包含函数名(不修改函数的调用方式)

a.把一个函数名当做实参传给另外一个函数

作用:在不修改被装饰函数源代码的情况下为其添加功能

def bar():
      print("in the bar")

def test1(func):  #首先定义了一个bar的函数
      print(func)  #相当于print(bar)
      func()       #相当于bar()

test1(bar)  #bar(门牌号)就是这个函数映射的内存地址
#输出
<function bar at 0x10197a950>
in the bar

先看下面例子:

def bar():
     pass

print(bar)
bar()   #bar()可以运行此函数
#输出
<function bar at 0x10217a950>

那么我们为什么要把bar传到test1里面去执行呢?直接bar()运行就好了啊:

import time
def bar():
     time.sleep(3)
     print("in the bar")

def test1(func):     # test1(bar)中的bar传给了func,相当于func = bar,那么func()可以运行
      start_time=time.time()  #计时,接着运行func()变为了bar(),同时运行bar函数,打印
      func()  #run bar()     
      stop_time=time.time()  #计时
      print("the func run time %s"%(stop_time-start_time))

test1(bar)  #  首先执行test1(),在test1中将bar传递给了func:相当于把bar的内存地址传给了变量func,回到我们所说的函数即变量,如x=1,y=x  y代表x,类似于bar是函数,意味着它也可以像变量一样进行赋值。
#输出
in the bar
the func run time 3.0033440589904785  #打印bar函数运行的时间

查看test1(bar)符合装饰器的原则吗?

1.没有修改源代码bar()

2.但是调用的方式变了,不是直接bar()运行,不符合原则,此种test(bar)的调用方式,在函数多次调用的情况下,由于调用次数太多,可能会不知道在哪里调用了bar的函数。

b.返回值中包含函数名

作用:不修改函数的调用方式

import time

def bar():
     time.sleep(3)
     print("in the bar")

def test2(func):
     print(func)
     return func

print(test2(bar))
#输出
<function bar at 0x10217a950>
<function bar at 0x10217a950>

有内存地址说明加上()就可以直接运行,那么

import time

def bar():
     time.sleep(3)
     print("in the bar")

def test2(func):
     print(func)
     return func

print(test2(bar))
test2(bar())      #首先执行test2(),在test2中将bar()传递给了func:相当于把bar()的返回值传给了变量func,那么就不符合高阶函数的定义
#输出
in the bar
None

所以我们需要改变运行方式:

t=test2(bar)
t()
#输出
<function bar at 0x10297a950>
in the bar

再改变——>>>符合高阶函数的定义:返回值中包含函数名(不修改函数的调用方式)

import time

def bar():
     time.sleep(3)
     print("in the bar")

def test2(func):
     print(func)
     return func

bar=test2(bar)
bar()
#输出
<function bar at 0x10217a950>
in the bar

3.嵌套函数

定义:在一个函数的函数体内,用def去声明一个函数def,而不是去调用它()

def foo():
    print("in the foo")
    def bar():
        print("in the bar")

bar()  #无法调用,def bar()身处函数中,我们所说的函数即变量,那么它存在于局部作用域,局部变量是不能被全部变量调用的

所以我们需要修正到:

def foo():
     print("in the foo")
     def bar():   #全局变量和局部变量,全局变量顶格写,在整个程序运行都存在,局部变量存在于过程或函数中,函数运行完就释放
          print("in the bar")
          bar()

foo()

高阶函数+嵌套函数=》装饰器

局部作用域和全局作用域的访问顺序:

x=0

def grandpa():
      x=1
      def dad():
            x=2
            def son():
                 x=3
                 print(x)
            son()
      dad()
grandpa()
#定义函数就是在定义变量,那么定义完变量后,需要进行调用
posted @ 2017-07-21 14:24  Mr.hu  阅读(121)  评论(0编辑  收藏  举报