python装饰器二(函数的有用信息,带参数的装饰器,多个装饰器装饰一个函数)

装饰器的本质是闭包
开放封闭原则
1.对扩展是开放的
    为什么要对扩展开放呢?
    我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
    为什么要对修改封闭呢?
    就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,
很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
局部作用域可以对全局作用域的变量进行引用
count = 1

def func1():
    print(count)
func1()
函数内部如果有变量名与全局变量名相同且对此变量进行改变,
Python 就会将你引用的那个变量视为局部定义的变量,但是局部没定义,
则他会报错
count = 1
#函数内部如果有变量名与全局变量名相同且对此变量进行改变,
#Python 就会将你引用的那个变量视为局部定义的变量,但是局部没定义,则他会报错。
def func1():
    count1 = count + 1
    print(count)
func1()

def func1():
    count = 3
    def inner():
        count = count + 1
    inner()
    print(count)
func1()
函数中如果使用global + 变量 必须是第一次使用这个变量
flag = True
def func1():

    if flag:
        print(333)
    global flag
    flag = False
func1()

flag = True
while flag:
    print(333)
    flag = False
    print(222)
for if while 没有开辟临时空间。
globals() locals()
locals :函数会以字典的类型返回 当前位置 的全部 局部变量。
globals:函数以字典的类型返回全部全局变量
def extendList(val,list=[]):
    list.append(val)
    # print(globals())
    print(locals())  # {'list': [1], 'val': 1}
    def inner():
        a = 3
        b = 4
        print(locals())
    inner()
    return list
ret = extendList(1)

print(globals())  # 'ret': [1]
print(locals())
 
def wrapper(f): # f = func1函数名
    def inner(*args, **kwargs):#函数的定义,集合
        print(333)
        ret = f(*args, **kwargs)  # func1(*(333))函数的调用,集合
        print(666)
        return ret  # 111
    return inner

@wrapper  # func1新变量 = wrapper(func1) = inner
def func1():
    print(111)
    return 222
func1()  # inner()  333 111 666  return ret 返回给inner(),
print(func1() ) # inner() 333 111 666 222
print(inner() ) #不能执行inner,因为他已经赋值给func1了。

def wrapper(f): # f = func2函数名
    def inner(*args, **kwargs):
        print(333)
        ret = f(*args, **kwargs)  # func2(*(1,2))
        print(666)
        return ret
    return inner

@wrapper  # func2(新变量) = wrapper(func2)      = inner
def func2(a, b):
    print(a, b)
func2(1,2)  # inner(1,2)  333 1 2  666
print(func2(1,2))   #333 1 2  666 None

def wrapper(f): # f = func3函数名
    def inner(*args, **kwargs):
        print(333)
        ret = f(*args, **kwargs)  # func3(*(1,2))
        print(666)
        return ret  # 555
    return inner

@wrapper  # func3新变量 = wrapper(func3)     = inner
def func3(a, b):
    print(a, b)
func3(2,3)  #333 2 3 666 return ret 返回给inner(),func3中没有返回值,所以没什么值返回。
print(func3(2,3)) # inner(2,3) 333 2 3 666 None   func3中没有返回值。

def wrapper(f): # f = func4函数名
    def inner(*args, **kwargs):
        print(333)
        ret = f(*args, **kwargs)  # func3(*(1,2))
        print(666)
        return ret  # 555
    return inner

@wrapper  # func3新变量 = wrapper(func4)     = inner
def func4(a, b):
    print(a, b)
    return 555
func4(2,3)  #333 2 3 666 return ret 返回给inner(),需要打印才能出现返回值555
print(func4(2,3)) # inner(2,3) 333 2 3 666  555
print(inner() ) #不能执行inner,因为他已经赋值给func4了。
函数带返回值的装饰器 (万能装饰器)
import time
def timmer(f):  # f = login函数名
    def inner(*args,**kwargs):  # args (2, 3)
        start_time = time.time()
        ret = f(*args,**kwargs)  # login() *(2, 3) 2,3
        end_time = time.time()
        print('此函数的执行时间%s' % (end_time - start_time))
        return ret
    return inner

@timmer  # login = timmer(login)  # inner 此login是新变量
def login(a,b):
    print(a,b)
    time.sleep(0.3)
    print('洗洗更健康...')
    return 666

print(login(2,3))  # inner(2,3)

2 3
洗洗更健康...
此函数的执行时间0.3001127243041992
666

def wrapper(f):#f=func 函数名
    def inner(*args,**kwargs):#定义,聚合(111,222)
        print(333)
        '执行函数之前的操作'
        ret=f(*args,**kwargs)# f=func 调用,打散 111 222
        '执行函数之后的操作'
        print(888)
        return ret
    return inner
@wrapper    #func新变量=wrapper(func) func 函数名
def func(*args,**kwargs):
    print(666)
func(111,222)#inner(111,222)



def wrapper(f):
    def inner(*args,**kwargs):
        '''执行被装饰函数之前的操作'''
        ret = f(*args,**kwargs)
        """执行被装饰函数之后的操作"""
        return ret
    return inner
函数的有用信息
函数内部想用外部的内容,用传参
函数外部想用内外部的内容,用return

def login(username, password):
    """
    此函数需要用户名,密码两个参数,完成的是登录的功能。
    :return: True 登录成功。 False登录失败。
    """
    # print(login.__name__)
    # print(login.__doc__)
    print('登录成功...')
    return True

print(login.__name__)
print(login.__doc__)

from functools import wraps
def wrapper(f):
    @wraps(f)
    def inner(*args,**kwargs):
        '执行函数之前的操作'
        ret=f(*args,**kwargs)
        '执行函数之后的操作'
        return ret
    return inner
@wrapper
def login():
    '''
    此函数需要用户名,密码两个参数,完成的是登录的额功能
    :return: True 登陆成功,False 登陆失败
    '''
    print('登陆成功...')
print(login.__name__)
print(login.__doc__)
login()

 


from functools import wraps
def wrapper(f):
    @wraps(f)#加上@wraps(f),可以从外部打印login 和login的注释。
    def inner(*args, **kwargs):
        """执行函数之前的操作"""
        ret = f(*args, **kwargs)
        """执行函数之后的操作"""
        return ret
    return inner

@wrapper
def login(username, password):
    """
    此函数需要用户名,密码两个参数,完成的是登录的功能。
    :return: True 登录成功。 False登录失败。
    """
    a = 2
    c = 4
    print('登录成功...')
    return True

print(login.__name__)
print(login.__doc__)
login()

for i in login.__dict__:
    print(i)
print(dir(login))
局部只能引用全局的变量,不能修改,如果要修改,global。
count = 1

def func4():
    count = count + 1
    print(count)

func4()


def func4():
    count = 3
    def inner():
        nonlocal count
        count = count + 1
        print(count)
    inner()
func4()
带参数的装饰器
import time
def timmer_out(flag1):#flag1=flag
    def timmer(f):
        def inner(*args,**kwargs):
            if flag1:
                start_time=time.time()
                ret=f(*args,**kwargs)
                time.sleep(0.3)
                end_time=time.time()
                print('执行效率为%s' % (end_time-start_time))
                return set
            else:
                ret=f()
                return set
        return inner
    return timmer

# flag=False
flag=True
@timmer_out(flag)#1 timme_out==timmer
                 #2 @与 timmer 结合变成我们熟悉的@timmer
def func1():
    print(111)

@timmer_out(flag)
def func2():
    print(222)

@timmer_out(flag)
def func3():
    print(333)

func1()
func2()
func3()

多个装饰器装饰一个函数

def wrapper1(func): # func = f函数名
    def inner1():
        print('wrapper1 ,before func')  # 2
        func()
        print('wrapper1 ,after func')  # 4
    return inner1


def wrapper2(func):  # func = inner1
    def inner2():
        print('wrapper2 ,before func')  # 1
        func()  # inner1()
        print('wrapper2 ,after func')  # 5
    return inner2

@wrapper2  # f = wrapper2(f) 里面的f新变量 = inner1 外面的f最新变量 = inner2
@wrapper1  # f = wrapper1(f) 里面的f函数名  外面的f新变量=inner1
def f():
    print('in f')  # 3

f()  # inner2()
'''
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
'''

def wrapper1(func): #func=f  1
    def inner1():
        print('wrapper1,before fun')    #7
        func()
        print('wrapper1,after func')    #9
    return inner1

def wrapper2(func): #func=inner1    2
    def inner2():
        print('wrapper2,before fun')    #6
        func()
        print('wrapper2,after func')    #10
    return inner2

def wrapper3(func): #func=inner2    3
    def inner3():
        print('wrapper3,before fun')    #5
        func()
        print('wrapper3,after func')    #11
    return inner3

@wrapper3   #f=wrapper3(f)  外f=inner2   wrapper3(f)=inner3  内f=inner3
@wrapper2   #f=wrapper2(f)  外f=inner1   wrapper2(f)=inner2  内f=inner2
@wrapper1   #f=wrapper1(f)  外f=f函数名  wrapper1(f)=inner1  内f=inner1
def f():
    print('in f')
f() #inner3()   4   8

'''
wrapper3,before fun
wrapper2,before fun
wrapper1,before fun
in f
wrapper1,after func
wrapper2,after func
wrapper3,after func
'''

tast

1.给每个函数写一个记录日志的功能,
功能要求:每一次调用函数之前,要将函数名称,时间节点记录到log的日志中。
所需模块:
import time
struct_time = time.localtime()
print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))
import time
def wrapper(f):

    def inner(*args,**kwargs):
        struct_time = time.localtime()
        time_nodes=time.strftime("%Y-%m-%d %H:%M:%S",struct_time)
        print(f.__name__)#根据需要写不同的函数
        print(time_nodes)
        with open('log',encoding='utf-8',mode=('a')) as f1:
            f1.write('在%s调用了%s\n' % (time_nodes,f))
            ret=f(*args,**kwargs)
            return ret
    return inner

@wrapper
def func1():
    time.sleep(0.2)
    print(111)
func1()

@wrapper
def func2():
    time.sleep(0.2)
    print(222)
func2()

@wrapper
def func3():
    time.sleep(0.2)
    print(333)
func3()

2,在编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,
后续的函数都无需再输入用户名和密码。这个作业之上进行升级操作:
设置两套密码,一套为京东账号密码,一套为淘宝账号密码保存在文件中。
设置四个函数,分别代表 京东首页,京东超市,淘宝首页,淘宝超市。
循环打印四个选项:东首页,京东超市,淘宝首页,淘宝超市。
供用户选择,用户输入选项后,执行该函数,四个函数都加上认证功能,只要登陆成功一次,
在选择其他函数,后续都无需输入用户名和密码。
相关提示:用带参数的装饰器。装饰器内部加入判断,验证不同的账户密码。
dic_status = {
    'username':None,
    'status':False,
}
def register(argv):
    def login(func):
        def inner(*args,**kwargs):
            '''被装饰函数执行之前的操作'''
            if dic_status['status']:
                ret = func(*args, **kwargs)
                return ret
            else:
                i = 1
                while i < 4:
                    with open(argv, encoding='utf-8')as f1:
                        username = input('请输入你的账号:').strip()
                        password = input('请输入你的密码:').strip()
                        for line in f1:
                            line = line.strip().split()
                        if username == line[0] and password == line[1]:
                            dic_status['username'] = username
                            dic_status['status'] = True
                            print('恭喜你登录成功')
                            ret = func(*args, **kwargs)
                            return ret
                        else:
                            print('您输入的账号或者密码错误,还剩余%s次机会' % (3 - i))
                        i += 1
        return inner
    return login

@register('京东')
def jingdong_home():
    print('欢迎%s登陆京东首页' % dic_status['username'])

@register('京东')
def jingdong_shop():
    print('欢迎%s登陆京东超市'% dic_status['username'])

@register('淘宝')
def taobao_home ():
    print('欢迎%s登陆淘宝首页'% dic_status['username'])

@register('淘宝')
def taobao_shop ():
    print('欢迎%s登陆淘宝超市'% dic_status['username'])

dic={
    1:jingdong_home,#在这里是函数名
    2:jingdong_shop,
    3:taobao_home,
    4:taobao_shop
}
goods=[
    {'name':'京东首页'},
    {'name':'京东超市'},
    {'name':'淘宝首页'},
    {'name':'淘宝超市'}
]
while True:
    # print('{}\n{}\n{}\n{}\n'.format(('1'+'\t'+'京东首页'),('2'+'\t'+'京东超市'),\
    # ('3'+'\t'+'淘宝首页'),('4'+'\t'+'淘宝超市')))
    print('***页面展示***')
    for num,goods_dic in enumerate(goods,1):
        print('\033[1;35;0m{}\t{}\033[0m'.format(num,goods_dic['name']))
    print('************')
    choice=input('请输入你的选择:Q或者q退出').strip()
    if choice.isdigit():
        choice = int(choice)
        if 0<choice<=len(dic):
            dic[choice]()
        else:
            print('您输入的数字超出范围,请重新输入:')
    elif choice.upper() == 'Q':
        break
    else:
        print('您输入的含有非数字字符,请重新输入:')


posted @ 2018-05-19 23:45  老虎死了还有狼  阅读(204)  评论(0编辑  收藏  举报