Python学习之路基础篇--11-12Python基础,函数的装饰器

  对于装饰器来说,就是在不改变函数的调用的情况下,对函数的前后增加了些许功能,这完全符合函数的 开放封闭 原则。装饰器的本质 其实就是一个闭包函数。

  这是一个装饰器的步骤图

def wrapper(func):  # 2
    def inner(*args,**kwargs):  # 5
        ret = func(*args,**kwargs)  # 6
        return ret  #10
    return inner   # 3

@wrapper  #shopping = wrappers(shooping)   # 1 --shopping = innner
def shopping(num):  #7
    print(num)  # 8
    return 1    # 9

print(shopping(5))  # 4

 

 

  这样你调 shopping 时, 真实情况是你在调用 inner 函数。如果 你想打印其函数名时打印的其实是 innner 函数。

from functools import wraps
def wrapper(func):  # 2
    @wraps(func)
    def inner(*args,**kwargs):  # 5
        ret = func(*args,**kwargs)  # 6
        return ret  #10
    return inner   # 3

@wrapper  #shopping = wrappers(shooping)   # 1 --shopping = innner
def shopping(num):  #7
    print(num)  # 8
    return 1    # 9

print(shopping(5))  # 4
print(shopping.__name__)  #以字符串的形式获取到函数名
print(shopping.__doc__)  #以字符串的形式获取到函数注释

  如果用内置的模块,wraps ,就可以轻松解决这个问题,使得所有的还和以前一样,其中wraps(),中要传入参数,参数应该与外层装饰器的形参一致。

 

 

  对于装饰器,如果你想取消个这装饰器的功能,现在给出的方法就只能是在装饰的外面在套一个装饰器,并设置一个定位符(一个全局变量)来控制其是否执行:

control = True
def outer(flag):
        def wrapper(func):
            def inner(*args,**kwargs):
                if flag:
                    print('函数执行前')
                    ret = func(*args,**kwargs)
                    print('函数执行后')
                    return ret
                else:
                    ret = func(*args, **kwargs)
            return inner
        return wrapper

@outer(control)# shoping = outer(shopping) = wapper(shoping) = inner(shopping) 只是要多一个参数进行判断
def shopping(num):
    print(num)
    return 1

shopping(5)

  

 

  多个装饰器进行嵌套,装饰器的糖的运行是,就近原则,离函数最近的糖先运行

def wrapper1(func):  #func--shopping
    def inner(*args,**kwargs):
        print('000函数执行前')
        ret = func(*args,**kwargs)
        print('000函数执行后')
        return ret
    return inner

def wrapper2(func):  #func--inner1
    def inner(*args,**kwargs):
        print('111函数执行前')
        ret = func(*args,**kwargs)  #这里的调用其实是使用 inner1() 函数
        print('111函数执行后')
        return ret
    return inner

@wrapper2
@wrapper1
def shopping(num):
    print(num)
    return 1

shopping(5)
'''
111函数执行前
000函数执行前
5
000函数执行后
111函数执行后
'''

 

 

  来个作业

# 在12 天作业 编写装饰器,为多个函数加上认证功能(用户的账号来源于文件),
# 要求登入一次成功,后续的函数都无需再输入用户和密码
def wrapper(func):
    def inner(*args, **kwargs):
        with open('ver', mode='r+',encoding='utf-8')as f:
           flag = f.read()
           if  flag:
                verification = input('>>>').strip()
                if verification == 'eli123':
                    # f.seek(0)
                    f.truncate(0,)
                    ret = func(*args, **kwargs)
                    return ret
           else:
               ret = func(*args, **kwargs)
               return ret
    return inner

@wrapper
def buy(num):
    print('买了{}个包子'.format(num))
@wrapper
def eat(num):
    print('吃了{}个包子'.format(num))
with open('ver',mode='w',encoding='utf-8') as f:
    f.write('aaa')
buy(3)
eat(2)

  这里利用了一个文件,在进行函数前,生成内容,然后文件中有内容时,要求验证 验证码,然后删除,方便第二次的验证。

 

 

# 2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
from functools import wraps
def wrapper(func):
    wraps(func)
    def inner(*args, **kwargs):
        with open('record',mode='a',encoding='utf-8') as f:
            f.write(func.__name__ + '\n')
        ret = func(*args, **kwargs)
        return ret
    return inner

@wrapper
def buy(num):
    print('买了{}个包子'.format(num))
@wrapper
def eat(num):
    print('吃了{}个包子'.format(num))

buy(3)
eat(2)

  与第一题相比,确实比较容易一点(之后学到时间模块,可以加入时间模块的)

 

posted on 2018-08-09 16:56  勤小兽  阅读(70)  评论(0编辑  收藏  举报

导航