python 装饰器

写代码要遵循开发封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:

  • 封闭:已实现的功能代码块
  • 开放:对扩展开发

故装饰器的出现就是解决以上问题的

一、什么是装饰器

  装饰器本质就是函数,功能是为其他函数附加功能

二、装饰器遵循的原则

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

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

三、实现装饰器的知识储备

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

 

装饰器的简单示例1:(在不修改源代码的基础上添加新的功能)

import time
def timmer(func):
    def wrapper():
        print(func)
        func()
    return wrapper
@timmer#就相当于是装饰器的功能,将被装饰的index加入了新功能,即index=timmer(index)#
def index():
    time.sleep(2)
    print("welcome to beijing")
index()

执行结果是:

<function index at 0x000000000251B8C8>
welcome to beijing

装饰器示例2:(在不修改源代码的基础上添加计算运行时间的新的功能)

 

# #计算运行时间
import time#导入模块
def timmer(func):#这时候相当于def timmer(func)是def timmer(index)
    def wrapper():
        print(func)  #打印index的内存地址
        start_time=time.time()#开始时间
        func()     #func()相当于index()#相当于执行index()原始函数
        stop_time=time.time()#结束时间
        print("run time is %s"%(stop_time-start_time))#第八步
    return wrapper#

@timmer#是装饰器的功能,将被装饰的index加入了新功能,即index=timmer(index)
def index():
    time.sleep(2)
    print("welcome to beijing")
index()#由于上面def index()是def timmer(index)(),timmer(index)的执行结果是wrapper,
# 故而执行index函数就相当于是执行wrapper()

执行结果是:

<function index at 0x00000000024CB8C8>
welcome to beijing
run time is 2.0001144409179688

如图示例:

 

  

 

什么叫高阶函数呢??

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

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

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

 

高阶函数示例1:(函数接受的参数是一个函数名)

def foo():
    print('from foo')
def foo_1(func):
    print('from foo_1')
    func()

def foo_2(func):
    print('from foo_2')
    return func
foo_1(foo)#将函数名foo当做参数
foo_2(foo)#将函数名foo当做参数

 执行结果是:

from foo_1
from foo
from foo_2

 高阶函数示例2:(函数的返回值是一个函数名)

def foo():
    print('from foo')
def foo_1(func):
    print('from foo_1')
    func()
    return func
foo=foo_1(foo)
print(foo)

执行结果是:

from foo_1
from foo
<function foo at 0x0000000001D13E18>

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

 

装饰器:

无参装饰器:

示例1:

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        print(func)#打印的是home的内存地址
        start=time.time()
        func(*args,**kwargs)#由于func为home,故而返回下面执行home函数,即home(“xuyuanyuan”)
        stop=time.time()
        print('run time is %s ' %(stop-start))
    return wrapper

@timmer#相当于home=timmer(home)
def home(name):
    time.sleep(2)
    print('welcome to %s home page' %name)
home('xuyuanyuan')#执行的是wrapper(“xuyuanyuan”),将xuyuanyuan当做参数传给wrapper(*args,**kwargs)这个函数

执行结果是:

<function home at 0x000000000254B8C8>
welcome to xuyuanyuan home page
run time is 2.0011146068573 

示例2:

##无参装饰器(有参函数)
import time
def timmer(func):
    def wrapper(*args,**kwargs):#wrapper('egon','123')
        start_time=time.time()
        func(*args,**kwargs) #相当于执行该auth('egon','123')函数,将egon 123当做参数传给函数auth(name,password),故而输出print('egon','123')
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
    return wrapper

@timmer  #auth=timmer(auth)
def auth(name,password):
    print(name,password)
auth('egon','123') #wrapper('egon','123')

 执行结果是:

egon 123
run time is 0.0

示例3:

##判断最大值,并输出它的运行时间
import time
def timmer(func):#相当于def timmer(my_max)
    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
@timmer#my_max=timmer(my_max)
def my_max(x,y):
    print('my_max function')
    res=x if x > y else y
    return res
res=my_max(1,2) #res=wrapper(1,2)
print('=====>',res)

执行结果是:

my_max function
run time is 0.0
=====> 2

  

有参装饰器(即2层闭包函数)

示例:

def auth2(auth_type):
    def auth(func):
        # print(auth_type)
        def wrapper(*args,**kwargs):
            if auth_type == 'file':
                with open("file.txt", mode="r", encoding="utf8") as f:
                    file_list = f.readlines()
                name=input('用户名: ')
                passwd=input('密码:')
                if name in file_list:  # 如果用户名在黑名单内
                    print("您的账户已锁定,请联系管理员!")

                if name == 'xyy' and passwd == '123':
                    print('auth successfull')
                    res=func(*args,**kwargs)#执行函数index()
                    return res
                else:
                    print('auth error')
            elif auth_type == 'sql':
                print('暂不支持')
        return wrapper
    return auth

@auth2(auth_type='file') #auth2(auth_type='sql')的返回结果是author,故而@auth 相当于#index=auth(index)
def index():
    print('welcome to inex page')
index()#运行函数index

执行结果是:

用户名: xyy
密码:123
auth successfull
welcome to inex page

 

多个装饰器的使用:

当需要使用多个装饰器的功能时,一般是先调用下面的@,再执行上面的@

举例说明:(给上述例子加入计算运行时间的功能)

import time#导入时间模块
current_login={'name':None,'login':False}

##定义运行时间函数
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        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 == 'xyy' 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
##调用了2个装饰器,先执行@auth2(auth_type='file')再运行@timmer,由上至下
@timmer##再执行这个
@auth2(auth_type='file') #@auth  #index=auth(index)##先执行这个
def index():
    print('welcome to inex page')
index()

执行结果是:

username: xyy
password: 123
auth successfull
welcome to inex page
run time is 12.809732437133789
welcome to inex page
run time is 0.0
posted @ 2017-04-16 11:14  白木潇潇夕  阅读(224)  评论(0编辑  收藏  举报