python3学习之路(13) 装饰器

什么是装饰器

装饰即修饰,意指为其他函数添加新功能;器即函数。

装饰器本质就是函数,功能是代码运行期间动态增加函数的功能的方式称之为装饰器。

装饰器遵循的原则

1、不修改被修饰函数的源代码

2、不修改被修饰函数的调用方式

#以下是一个显示函数运行时间的修饰器
import time
def timmer(func): #func=test
    def wrapper():
        # print(func)
        start_time=time.time()
        func() #就是在运行test()
        stop_time = time.time()
        print('运行时间是%s' %(stop_time-start_time))
    return wrapper

@timmer #test=timmer(test)
def test():
    time.sleep(3)
    print('test函数运行完毕')
test()



实现装饰器的知识储备:装饰器 = 高阶函数 + 函数嵌套 + 闭包

高阶函数的定义(满足以下条件任意一个,都可称之为高阶函数):

1、函数接收的参数是一个函数名
2、函数的返回值时一个函数名

#高阶函数例子
def foo():
    print('我的函数名作为参数传给高阶函数')
def gao_jie1(func):
    print('我就是高阶函数1,我接收的参数名是%s' %func)
    func()

def gao_jie2(func):
    print('我就是高阶函数2,我的返回值是%s' %func)
    return func

gao_jie1(foo)
gao_jie2(foo)


#把函数当做参数传给高阶函数
import time
def foo():
    print('from the foo')

def timmer(func):
    start_time=time.time()
    func()
    stop_time=time.time()
    print('函数%s 运行时间是%s' %(func,stop_time-start_time))
timmer(foo)
#总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式


#把函数名当做参数传给高阶函数,高阶函数直接返回函数名
import time
def foo():
    print('from the foo')

def timmer(func):
    start_time=time.time()
    return func
    stop_time=time.time()
    print('函数%s 运行时间是%s' %(func,stop_time-start_time))
foo=timmer(foo)
foo()
#总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能



高阶函数总结:
1.函数接收的参数是一个函数名
  作用:在不修改函数源代码的前提下,为函数添加新功能,
  不足:会改变函数的调用方式
2.函数的返回值是一个函数名
  作用:不修改函数的调用方式
  不足:不能添加新功能

函数嵌套

def father(name):
    print('from father %s' %name)
    def son():
        print('from son')
        def grandson():
            print('from grandson')
        grandson()
    son()

father('erbiao')



闭包

#闭包:在一个作用域里放入定义变量,相当于打了一个包

def father(name):
    def son():
        # name='alex'
        print('我爸爸是 [%s]' %name)
        def grandson():
            # name='wupeiqi'
            print('我爷爷是 [%s]' %name)
        grandson()
    son()

father('erbiao')



一个简单的装饰器

import time

def timmer(func):	# func = test
	def wrapper():
		start_time = time.time
		func()	#运行test()
		stop_time = time.time
		print(“运行时间是 %s”,%(stop_time-start_time))
	return wrapper

@timmer
def test():
	time.sleep(5)
	print("test函数运行完毕")

test()
#不使用装饰器时,调用方法如下:
#	res = timmer(test)	#返回wrapper地址
#	tes()	#执行wrapper()



为装饰器加上返回值

#函数默认返回值是None
#以上函数test()若想定义返回值,则需要在timmer()中使用return语句
#因为使用装饰器后,test()函数运行在最后一行在timmer()中,如:

import time
def timmer(func):
    def wrapper():
        start_time = time.time()
        res = func()
        stop_time =time.time()
        print("函数的运行时间是 %s" %(stop_time - start_time))
        return res
    return wrapper

@timmer
def test():
    time.sleep(3)
    print("test函数已运行完毕")
    return "这是test()的返回值"

print(test())



装饰器传参实例

#一个简单的装饰器传参实例
#最终函数会在装饰器函数中运行,因此传参要传入装饰器函数
#装饰器在传参时,要保证和函数穿的参数数量一致
import time
def timmer(func):
    def wrapper(name,age):
        start_time = time.time()
        res = func(name,age)
        stop_time =time.time()
        print("函数的运行时间是 %s" %(stop_time - start_time))
        return res
    return wrapper

@timmer
def test(name,age):
    time.sleep(3)
    print('我是%s,我%s了' %(name,age))
    return "这是test()的返回值"

print(test("erbiao","35")) 



装饰器传入不定长参数

#在向装饰器传入参数过程中,不同的函数可能传入参数数量不一样
#使用位置参数(*args)和关键字参数(**kwarg)可传入不定长参数
#*args表示传入参数是元组,**kwargs表示传入参数是字典
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        stop_time = time.time()
        print('函数[%s],运行时间是[%s]' % (func, stop_time - start_time))
    return wrapper

@timer
def test(*args,**kwargs):
    print("*args",args)
    print("**kwargs",kwargs)

res = test("我","x","y","z",a=1,b=2)
print(res)



装饰器模拟认证功能

user_list=[
    {'name':'alex','passwd':'123'},
    {'name':'linhaifeng','passwd':'123'},
    {'name':'wupeiqi','passwd':'123'},
    {'name':'yuanhao','passwd':'123'},
]
current_dic={'username':None,'login':False}


def auth_func(func):
    def wrapper(*args,**kwargs):
        if current_dic['username'] and current_dic['login']:
            res = func(*args, **kwargs)
            return res
        username=input('用户名:').strip()
        passwd=input('密码:').strip()
        for user_dic in user_list:
            if username == user_dic['name'] and passwd == user_dic['passwd']:
                current_dic['username']=username
                current_dic['login']=True
                res = func(*args, **kwargs)
                return res
        else:
            print('用户名或者密码错误')

    return wrapper

@auth_func
def index():
    print('欢迎来到京东主页')

@auth_func
def home(name):
    print('欢迎回家%s' %name)

@auth_func
def shopping_car(name):
    print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))

print('before-->',current_dic)
index()
print('after--->',current_dic)
home('产品经理')
# shopping_car('产品经理')



posted @ 2018-09-10 16:37  二表  阅读(118)  评论(0)    收藏  举报