函数装饰器

一 什么是装饰器

装饰器补充:http://www.cnblogs.com/luchuangao/p/6842293.html

 

器即函数

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

装饰器定义:本质就是函数,功能是为其他函数添加新功能 #装饰器本身就是函数,被装饰的也是函数。

 

为什么要用装饰器:
及开放封闭原则。
代码上线后,就是为了尽量避免修改,不修改原函数的源代码和调用方式,并添加新的功能。 # 函数及定义和使用。

 

装饰器语法:

在被装饰上的正上方写一个@,它会把@这一行下面这一行的函数传递到函数里,再重新赋值给index。

func就是index函数,print(func)返回得是index内存地址。

无参装饰器:

(1):

输出:
welcome to oldboy
run time is 3.000171661376953

执行过程:

# 函数应该先定义后使用。
import time
def timmer(func): # 定义函数就相当于定义变量名,就相当于把函数的代码绑定到一个名字上面了。 #1,定义变量名 #3 func值就是index
    def wrapper(): #4 开始执行timmer里面的代码,只要碰到def就跟定义变量名一样,它里边定义的代码全不用管,只要不执行就不用管它。#7
        start_time=time.time() #8
#        print(func) 
        func() #9 func就是最原始的index
        stop_time=time.time() #14
        print('run time is %s' %(stop_time-start_time)) #15
    return wrapper #5 return wrapper 就是return wrapper的内存地址

# index=timmer(index)  
@timmer #2 timmer要运行timmer(index),所以要跳回去 #10
def index(): #11
    time.sleep(3) #12
    print('welcome to oldboy') #13
index() #6 index就是wrapper函数,wrapper是一个闭包函数,里边包含了一个状态,就是func。

(2): # 第一次是home,第二次是home("name")

输出:
welcome to dragon home page
run time is 2.0001144409179688
egon 123
run time is 0.0
------------
run time is 0.0

注意:传参数,需要加上*args,**kwargs

(3):

输出:
my_max function
run time is 0.0
-------- 2

注意:如果原函数需要有返回值,则装饰器也需要设置return res。完整正确的无参装饰器写法就是以上写法。 

有参装饰器:

(1): #第一步是函数()的效果,第二步是@auth的效果

 输出:还他妈的不会玩

 

#有参函数执行流程
def auth2(auth_type): #1 #3
    def auth(func): #4 #6
        def wrapper(*args,**kwargs): #7 #10
            if auth_type == 'file': #11
                name=input('username: ')
                password=input('password: ')
                if name == 'zhejiangF4' and password == 'sb945':
                    print('auth successfull')
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('auth error')
            elif auth_type == 'sql': #12
                print('还他妈不会玩') #13
        return wrapper #8
    return auth #5

@auth2(auth_type='sql') #2
def index():
    print('welcome to inex page')

# @auth
# def home():
#     print('welcome to home page')
index() #9

多个装饰器:

#多个无参装饰器:
# @aaa
# def func():
#     pass
#
# func=aaa(func)

# @ccc
# @bbb
# @aaa
# def func():
#     pass
#
# func=ccc(bbb(aaa(func)))

#多个有参装饰器
# @ccc('c')
# @bbb('b')
# @aaa('a')
# def func():
#     pass
#
# func=ccc('c')(bbb('b')(aaa('a')(func)))

多个装饰器应用:

import time
current_login={'name':None,'login':False}

def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)  #my_max(1,2)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper

def auth2(auth_type='file'):
    def auth(func):
        # print(auth_type)
        def wrapper(*args,**kwargs):
            if current_login['name'] and current_login['login']:
                res=func(*args,**kwargs)
                return res
            if auth_type == 'file':
                name=input('username: ')
                password=input('password: ')
                if name == 'luchuan' and password == '123':
                    print('auth successfull')
                    res=func(*args,**kwargs)
                    current_login['name']=name
                    current_login['login']=True
                    return res
                else:
                    print('auth error')
            elif auth_type == 'sql':
                print('还他妈不会玩')
        return wrapper
    return auth

@timmer
@auth2(auth_type='file') #@auth  #index=auth(index)
def index():
    print('welcome to inex page')

@auth2()
def home():
    print('welcome to home page')



#调用阶段
index()
home()

装饰器帮助信息补充:

import time
from functools import wraps
def timmer(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        'sssssssssssss' # 不加wraps,就会返回'sssssss'帮助信息
        start_time=time.time()
        func(*args,**kwargs) #home(name)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
    return wrapper


@timmer
def func(x):
    'func test'
    print(x)

func(1)
print(func.__doc__)  # 查看帮助信息的两种方式
# print(help(func))

#不加wraps,输出sssssssss
#加上wraps,则输出:from test

二 装饰器需要遵循的原则

1.不修改被装饰函数的源代码(开放封闭原则)

2.为被装饰函数添加新功能后,不修改被修饰函数的调用方式

三 实现装饰器知识储备

装饰器=高阶函数+函数嵌套+闭包

装饰器:一个外部函数、一个内部函数、一个return 、如果是有参装饰器,外部再包一层函数。

四 高阶函数

高阶函数定义:
1.函数接收的参数是一个函数名

2.函数的返回值是一个函数名

3.满足上述条件任意一个,都可称之为高阶函数

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)

高阶函数示范
高阶函数示范
#高阶函数应用1:把函数当做参数传给高阶函数
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),改变了函数的调用方式

把函数当做参数传给高阶函数
把函数当做参数传给高阶函数
#高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名
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('林海峰')

六 闭包

'''
闭包:在一个作用域里放入定义变量,相当于打了一个包
'''
def father(name):
    def son():
        # name='alex'
        print('我爸爸是 [%s]' %name)
        def grandson():
            # name='wupeiqi'
            print('我爷爷是 [%s]' %name)
        grandson()
    son()

father('林海峰')

七 无参装饰器

无参装饰器=高级函数+函数嵌套

基本框架

1 #这就是一个实现一个装饰器最基本的架子
2 def timer(func):
3     def wrapper():
4         func()
5     return wrapper

加上参数

1 def timer(func):
2     def wrapper(*args,**kwargs):
3         func(*args,**kwargs)
4     return wrapper

加上功能

1 import time
2 def timer(func):
3     def wrapper(*args,**kwargs):
4         start_time=time.time()
5         func(*args,**kwargs)
6         stop_time=time.time()
7         print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time))
8     return wrapper

 加上返回值

1 import time
2 def timer(func):
3     def wrapper(*args,**kwargs):
4         start_time=time.time()
5         res=func(*args,**kwargs)
6         stop_time=time.time()
7         print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time))
8         return res
9     return wrapper

使用装饰器

1 def cal(array):
2     res=0
3     for i in array:
4         res+=i
5     return res
6 
7 cal=timer(cal)
8 cal(range(10))

语法糖@

1 @timer  #@timer就等同于cal=timer(cal)
2 def cal(array):
3     res=0
4     for i in array:
5         res+=i
6     return res
7 
8 cal(range(10))

八 装饰器应用示例

user_list=[
    {'name':'alex','passwd':'123'},
    {'name':'linhaifeng','passwd':'123'},
    {'name':'wupeiqi','passwd':'123'},
    {'name':'yuanhao','passwd':'123'},
]

current_user={'username':None,'login':False}

def auth_deco(func):
    def wrapper(*args,**kwargs):
        if current_user['username'] and current_user['login']:
            res=func(*args,**kwargs)
            return res
        username=input('用户名: ').strip()
        passwd=input('密码: ').strip()

        for index,user_dic in enumerate(user_list):
            if username == user_dic['name'] and passwd == user_dic['passwd']:
                current_user['username']=username

                current_user['login']=True
                res=func(*args,**kwargs)
                return res
                break
        else:
            print('用户名或者密码错误,重新登录')

    return wrapper

@auth_deco
def index():
    print('欢迎来到主页面')

@auth_deco
def home():
    print('这里是你家')

def shopping_car():
    print('查看购物车啊亲')

def order():
    print('查看订单啊亲')

print(user_list)
# index()
print(user_list)
home()

无参装饰器
无参装饰器
user_list=[
    {'name':'alex','passwd':'123'},
    {'name':'linhaifeng','passwd':'123'},
    {'name':'wupeiqi','passwd':'123'},
    {'name':'yuanhao','passwd':'123'},
]

current_user={'username':None,'login':False}
def auth(auth_type='file'):
    def auth_deco(func):
        def wrapper(*args,**kwargs):
            if auth_type == 'file':
                if current_user['username'] and current_user['login']:
                    res=func(*args,**kwargs)
                    return res
                username=input('用户名: ').strip()
                passwd=input('密码: ').strip()

                for index,user_dic in enumerate(user_list):
                    if username == user_dic['name'] and passwd == user_dic['passwd']:
                        current_user['username']=username
                        current_user['login']=True
                        res=func(*args,**kwargs)
                        return res
                        break
                else:
                    print('用户名或者密码错误,重新登录')
            elif auth_type == 'ldap':
                print('巴拉巴拉小魔仙')
                res=func(*args,**kwargs)
                return res
        return wrapper
    return auth_deco


#auth(auth_type='file')就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type='file')
#就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数
@auth(auth_type='ldap')
def index():
    print('欢迎来到主页面')

@auth(auth_type='ldap')
def home():
    print('这里是你家')

def shopping_car():
    print('查看购物车啊亲')

def order():
    print('查看订单啊亲')

# print(user_list)
index()
# print(user_list)
home()

带参装饰器
带参装饰器

 

参考链接:http://www.cnblogs.com/linhaifeng/articles/6140395.html

参考链接:http://www.cnblogs.com/yuanchenqi/articles/5828233.html#3503895

posted @ 2017-04-09 17:27  luchuangao  阅读(303)  评论(0编辑  收藏  举报