Python-Day 5-装饰器

一、定义

1、装饰器:本质是函数。

2、功能:用来装饰其他函数,顾名思义就是,为其他的函数添加附件功能的。

3、原则:不能修改被装饰函数的源代码、不能修改被装饰函数的调用方式

4、函数即"变量", 高阶函数+嵌套函数 => 装饰器

def test():
    print("LOVE")
#正确写法,没有修改源码
def test1():
    print("LOVE ME")
#错误写法,不能修改源码 def test1(): print("LOVE ME") test() #调用 test1()

 二、函数即变量

1、python的内存机制

在python解释器中,有一个概念叫做引用基数,例如,x=1这个b变量,先在内存当中把1这个值存放下来,这个x其实就是1的门牌号,x=1就是对1的一次引用。

python等到1所对应的门牌号都没有了,就会把1给清掉,这个也是python的内存回收机制。 

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

#变量
x = 1
#函数
def test():
    pass

  

2、函数在内存的表现形式

①test函数在fex函数之后定义

def test():
    print("in test")
    fex()

def fex():
    print("in fex")

test()

#结果
in test
in fex 

test函数在fex函数之前定义

def fex():
    print("in fex")

def test():
    print("in test")
    fex()
test()
#结果 in test in fex 

上面两种写法,输出结果是一样的

test函数在fex函数之后声明


def test():
print("in test")
fex()

test()

def fex():
print("in fex")
#结果 Traceback (most recent call last): File "/Users/bianbian/PycharmProjects/test/test10.py", line 5, in <module> test() NameError: name 'test' is not defined

因为在执行test函数时,当调用fex函数时,fex还函数还定义,所以报错。

三、高阶函数

实现高阶函数的条件:把一个函数名当做实参传给另外一个函数,且返回值中包含函数名

1、把一个函数名当做实参传给另外一个函数

import time
def fex():
    time.sleep(3)
    print("in the fex")
def test(func):
    print(func)
    start_time = time.time()
    func()
    stop_time = time.time()
    print("the func run the is %s" % (stop_time - start_time))
#没有修改fex的代码
test(fex) #把fex函数名当做实参传到test中
#结果
<function fex at 0x10df3b268>
in the fex
the func run the is 3.0029611587524414

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

2、返回值中包括函数名

import time
def fex():
    time.sleep(3)
    print("in the fex")
def test1(func):
    print(func)
    return(func) #返回函数的内存地址

test=test1(fex)
fex()
#没有改变fex函数的调用方式
#结果
<function fex at 0x1090ab268>
in the fex

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

四、嵌套函数

在一个函数的函数体内,用def 去声明一个函数,而不是去调用其他函数,称为嵌套函数。

def fex():
    print("in fex")
    def fun():
        #在fex函数体内声明一个函数fun
        print("in fun")
    fun()
fex()

变量的作用域:从里往外找,一层一层的的找。 

x=0
def test():
    x=1
    def test1():
        x=2
        def test2():
            x=3
            print(x)
        test2()
    test1()
test()
#结果
3

 五、装饰器

装饰器实现的条件:高阶函数+嵌套函数 =>装饰器

import time
#定义内置函数
def timmer(func): #timmer(test) func=test
    def fex():
        start_time=time.time()
        func() #run test()
        stop_time=time.time()
        print("the func run time is %s" %(start_time-stop_time))
    return fex
#装饰test函数
@timmer  # 相当于test = timmer(test)
def test():
    time.sleep(3)
    print("in the test")
#直接执行test函数
test()

#结果
in the test
the func run time is -3.0014219284057617 

执行步骤:

  1. 执行timmer函数,timmer(test) 返回值赋值给test变量,即test=timmer(test)
  2. 此时的test的值是执行timmer函数返回值fex,即test=fex
  3. 所以执行test,其实就是执行的是fex函数,test()其实就是执行fex函数。

 1、执行函数带参数

import time
#定义内置函数
def timmer(func): #timmer(test) func=test
    def fex():
        start_time=time.time()
        func() #run test()
        stop_time=time.time()
        print("the func run time is %s" %(start_time-stop_time))
    return fex
#装饰test1函数

@timmer  # 相当于test1 = timmer(test1)
def test1(age,name):
    print("name:%s,age:%s"%(age,name))
#直接执行test函数
test1()
#结果
Traceback (most recent call last):
  File "/Users/bianbian/PycharmProjects/test/test11.py", line 16, in <module>
    test1()
  File "/Users/bianbian/PycharmProjects/test/test11.py", line 6, in fex
    func() #run test()
TypeError: test1() missing 2 required positional arguments: 'age' and 'name'

 因为这边执行的test1函数其实就是执行的fex函数,fex函数体内的func()其实就是执行test1函数,但是,test1需要传入name和age两个参数,所以报错。那怎么解决呢?传入参数!

   但是你又不能确定传入几个参数,所以用非固定参数传参

import time
#定义内置函数
def timmer(func): #timmer(test) func=test
    def fex(*args,**kwargs):#传入非固定参数
        start_time=time.time()
        func(*args,**kwargs) #传入非固定参数
        stop_time=time.time()
        print("the func run time is %s" %(start_time-stop_time))
    return fex

#不带参数
@timmer
def test1(): # 相当于test1 = timmer(test1)
    time.sleep(3)
    print("in the test1")
#带参数
@timmer  # test2 = timmer(test2)
def test2(age,name):
    print("name:%s,age:%s"%(age,name))
#调用
test1()
test2("bianbian",18)

#结果
#test1
in the test1
the func run time is -3.0028131008148193
#test2
name:bianbian,age:18
the func run time is -1.5020370483398438e-05

 2、执行函数有返回值

如果,被调函数的有返回值??

def timmer(func): #timmer(test) func=test
    def fex(*args,**kwargs):#传入非固定参数
        res=func(*args,**kwargs) #传入非固定参数
        return res
    return fex

#不带参数
@timmer
def test1(): # 相当于test1 = timmer(test1)
    print("in the test1")
    return "from the test1"  # 执行函数test1有返回值
res = test1()
print(res)

#结果
in the test1
from the test1

 通过上面的例子,可以看出,就是在内置函数中把传入参数的执行结果赋给res,然后再返回res变量。

3、带参数的装饰器

之前装饰器都是没有带参数的,但是访问不到页面时,你用的验证的方式来源不同,这时你该怎么办?  

name,password="bianbian","bfj123321"
def auth(auth_type):#传递装饰器的参数
    print("auth_type",auth_type)
    def outer_wrapper(func):# 将被装饰的函数作为参数传递进来
        def wrapper(*args,**kwargs):# 将被装饰的函数作为参数传递进来
            print("wrapper func args",*args,**kwargs)
            username=input("Username:").strip()
            password=input("Password:").strip()
            if auth_type == "local":
                if name == username and password == password:
                    print("%s has passed authentication"%name)
                    res=func(*args,**kwargs)
                    print("--------after authentication")
                    return res
                else:
                    exit("Invalid username or password")
            elif auth_type == "ldap":
                pass
        return wrapper
    return outer_wrapper
def index():
    print("Welcome to index")
@auth(auth_type="local") #带参数装饰器
def home():
    print("Welcome to home page")
    return "from home"
@auth(auth_type="ldap") #带参数装饰器
def bbs():
    print("Welcome to bbs page")
index()
home()
bbs()

 结果:

可以看出,执行步骤:

  1. outer_wrapper = auth(auth_type="local")
  2. home = outer_wrapper(home)
  3. home()

所以这个函数的作用分别是:

  1. auth(auth_type) 传递装饰器的参数
  2. outer_wrapper(func) 把函数当做实参传递进来
  3. wrapper(*args,**kwargs) 真正执行装饰的函数
 
 

 

原文地址:https://www.cnblogs.com/bianfengjie/p/10839410.html