装饰器进阶

1.装饰器有参数(方便控制是否装饰)

import time
FLAG=False   #在装饰器中传一个参数,控制是否加上装饰
def timeer_out(flag):
    def time2(f):  # 传入的实际上是func1函数的内存地址
        def inner(*args, **kwargs):
            if flag==True:
                startx = time.time()
                ret = f(*args, **kwargs)
                endx = time.time()
                print(endx - startx)
                return ret
            else:
                ret = f(*args, **kwargs)
                return ret
        return inner
    return time2

@timeer_out(FLAG)            #time2=timeer_out(FLAG)
def func2(a):
    print(a)
    list1 = [1, 2, 3, 4, 5]
    s = int(input("请输入一个值:"))
    list1.append(s)
    for i in list1:
        print(i, end='   ')
    print('
')
    return list1
#func2=time2(func2)  #使用闭包



@timeer_out(FLAG)
def peinrx():
    print("cccccc")
    time.sleep(0.1)

a='开始:'
ret=func2(a)
print(ret)
peinrx()

2.多个装饰器装饰同一个函数

def wrapper1(func):
    def inner(*args,**kwargs):
        print('装饰1之前')
        func()
        print("装饰1之后")
    return inner

def wrapper2(func):
    def inner(*args,**kwargs):
        print("装饰2之前")
        func()
        print("装饰2之后")
    return inner

# @wrapper2
# @wrapper1
# def f():
#     print("被装饰的函数")
#
# f()
# 装饰2之前
# 装饰1之前
# 被装饰的函数
# 装饰1之后
# 装饰2之后

@wrapper1
@wrapper2
def f():
    print("被装饰的函数")

f()
# 装饰1之前
# 装饰2之前
# 被装饰的函数
# 装饰2之后
# 装饰1之后

3.一个简单的爬取网页的示例
  本来是不需要自己创建那个文件的,f=open那一行,但不知为何我的pycharm会报错,无奈之下先这么写了

import os
from urllib.request import urlopen
def cache(func):
    def inner(*args,**kwargs):
        #判断
        if os.path.getsize('webcache'):     #判断是否已经有函数
            with open('webcache', "rb") as f:
                return f.read()
        ######
        ret=func(*args,**kwargs)
        with open('webcache',"wb") as f:
            f.write(b'---'+ret)           #已经存在的,所以
        return ret
    return inner


@cache
def get(url):
    code=urlopen(url).read()   #这是一个bytes
    return code

f=open('webcache',"ab")
f.close()
ret=get('http://www.baidu.com')
print(ret)
ret=get('http://www.baidu.com')
print(ret)
ret=get('http://www.baidu.com')
print(ret)
ret=get('http://www.baidu.com')
print(ret)
ret=get('http://www.sanguosha.com')
print(ret)

4.第二个示例

#1.编写装饰器,为多个函数加上认证的功能,(用户的账号密码来源于文件)。
要求成功登陆一次,后续的函数无需输入用户名和密码 #只能创建一个全局变量,否则adddel切换就要在输入
#2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
FLAG=False
def login(func):
    def inner(*args,**kwargs):
        global FLAG
        '''登陆程序'''
        if FLAG:        #如果已经是登陆成功了,就先走了,不需要输入
            with open('log','a',encoding='utf-8') as f:
                f.write(func.__name__+'
')
            ret = func(*args, **kwargs)
            return ret
        else:
           username=input("用户名:")
           password=input("密码:")
           if username=='usern' and password=='passw':
              FLAG=True
              with open('log', 'a', encoding='utf-8') as f:
                  f.write(func.__name__ + '
')
              ret=func(*args,**kwargs)
              return ret
           else:
              print("登陆失败!")
    return inner

@login
def shoplist_add():
    print("增加一件物品")

@login
def shoplist_del():
    print("删除一件物品")


while(1):
    a=int(input("请选择操作  1.增加  2.删除  3.退出
"))
    if a==1:
        shoplist_add()
    elif a==2:
        shoplist_del()
    elif a==3:
        break

 5.再来一个示例。

  介绍两个函数__name__和__doc__

#记现象
#functools.wraps
#带参数的装饰器
#多个装饰器装饰同一个函数
#有很多个函数都用装饰器装饰过了,现在要全部去掉装饰,然后又重新再加上装饰

# def outer(*args,**kwargs):
#     print(args)
#     print(*args)
#
#
# outer(1,2,[1,2],3,4,**{'name':9})    #outer(*[1,2,3,4])   #outer(
# # (1, 2, 3, 4)
# 1 2 3 4    第二个变成散的
#接收就是聚合,使用就要打散,**kwargs,用*kwargs就是打散

flag1=1

from functools import wraps
def wrapper(func):
    @wraps(func)             #给内部的函数装饰一下,使holiday()原函数仍然存在。就和inner有区别
    def inner(*args,**kwargs):
        print("之前")
        ret=func(*args,**kwargs)
        print("之后")
        return ret
    return inner

@wrapper
def holiday(day):
    x=input("你想放几天假?")
    print("不是放%s天假,而是一共放%s天假"%(day,x))
    return x

ret=holiday(2)
print(ret)
print(holiday.__name__)

falg2=2
#
# def func2():
#     #打印
#     '''
#     只要胆子大,天天都是假
#     :return:
#     '''
#     print("cccc")
#
# print(func2.__name__)   #查看函数名
# print(func2.__doc__)    #查看注释
原文地址:https://www.cnblogs.com/lowislucifer/p/10979749.html