20 python学习函数闭包与装饰器

第九篇 装饰器

http://www.cnblogs.com/linhaifeng/articles/6140395.html

复习

 
age=10
res=True if age > 10 else False  #三元表达式

l=['a' for i in range(10)]
g_l=('a' for i in range(10)) #生成器表达式



def test():
    for i in range(4):
        yield i                            #是用时候,生成器只能历遍一次哦
t=test()       #这里面没有值,生成器取值是执行一个next才会有一个yield输出 
              # 不执行的话就不产生值
print(t)    #<generator object test at 0x00000000028E8150>
print(list(t)) # [0, 1, 2, 3]
for i in t:  #0 1 2 3 给在了t内, 遍历t
    print(i)

t1=(i for i in t)      #生成器t1 表达式 = 历遍生成器t   
       #  前边不能有print(list(t))或者for i in t:  遍历t会导致输出t1没有了空了,输出[]
print(t1)      #<generator object <genexpr> at 0x00000000025D81A8>
print(list(t1))    #  遍历生成器t1内并且以list形式打印[0, 1, 2, 3]    ???
         # 这不是和print(list(t)) 一样吗,为什么要多余变成t1呢


t1=(i for i in t)   #生成器取值是执行一个next才会有一个yield输出 
                   # 不执行的话就不产生值,生成器只能走一次,不能倒着走
# t1,t2里面都没有值,只有next才遍历里面的值
t2=(i for i in t1)
print(list(t1))   #这里把t1的值取空了, t2 就没了
print(list(t2))
输出      生成器只能历遍一次哦
[0, 1, 2, 3]
[]
 

第九篇 装饰器

本质是函数

http://www.cnblogs.com/linhaifeng/articles/6140395.html

装饰器定义:本质就是函数,功能是为其他函数添加新功能
原则
1.不修改被装饰函数的源代码(开放封闭原则)
2.为被装饰函数添加新功能后,不修改被修饰函数的调用方式

装饰器=高阶函数+函数嵌套+闭包
import time
def cal(l):
    start_time=time.time()
    res=0
    for i in l:
        time.sleep(0.1)
        res+=i
    stop_time = time.time()
    print('函数的运行时间是%s' %(stop_time-start_time))
    return res

print(cal(range(100)))       #输出函数的运行时间是10.06001877784729           4950
# 装饰器定义:本质就是函数,功能是为其他函数添加新功能
# 原则
# 1.不修改被装饰函数的源代码(开放封闭原则)
# 2.为被装饰函数添加新功能后,不修改被修饰函数的调用方式
#
# 装饰器=高阶函数+函数嵌套+闭包

import time

def cal(l):
    start_time=time.time()
    res=0
    for i in l:
        time.sleep(0.1)
        res+=i
    stop_time = time.time()
    print('函数的运行时间是%s' %(stop_time-start_time))
    return res

print(cal(range(100)))       #输出函数的运行时间是10.06001877784729           4950

装饰器预演

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time = time.time()
        print('函数运行时间是%s' %(stop_time-start_time))
        return res
    return wrapper

高阶函数

高阶函数定义:
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
3.满足上述条件任意一个,都可称之为高阶函数

1.函数接收的参数是一个函数名
import time
def foo():
    time.sleep(3)
    print('你好啊林师傅')

def test(func):
    print(func)       #打印输入函数func函数的内存地址
    start_time=time.time()
    func()      #执行
    stop_time = time.time()
    print('函数运行时间是  %s' % (stop_time-start_time))      #计算func函数的运行时间

test(foo)
输出
<function foo at 0x00000000003F1E18>
你好啊林师傅
函数运行时间是  3.000171422958374
已经能完成,在更改原代码的情况下添加新的功能
但是违反装饰器的原则

2.函数的返回值是一个函数名
def foo():
    print('from the foo')
def test(func):
    return func

res=test(foo)
# print(res)  #函数地址
res()     #from the foo

foo=test(foo)   #赋值(地址)的参数名和输入一样,
                 执行foo函数也是foo(),实现装饰器不改变函数使用方式
# # print(res)
foo()

import time
def foo():
    time.sleep(3)
    print('来自foo')

不修改foo源代码
不修改foo调用方式


多运行了一次foo,不合格
def timer(func):
    start_time=time.time()
    func()
    stop_time = time.time()
    print('函数运行时间是  %s' % (stop_time-start_time))
    return func         #调用func,输出func,然后赋值给同函数名foo,
                        # foo源代码,调用方式都不变,但是可以添加foo的功能
foo=timer(foo)         #多运行了一步func,后return func又运行一次
foo()

函数嵌套

嵌套 在函数内定义另一个函数,
递归 在函数内调用自己
def bar():
    print('from bar')

def foo():
    print('from foo')
    def test():
        pass

def father(auth_type):  #函数嵌套 ,一层是一个包的层级信息    包:一层套一层,类似箱子套箱子    闭:封装变量 ,当层变量+(函数即变量)
    # print('from father %s' %name)
    def son():
        name='linhaifeng_1'
        print('我的爸爸是%s' %name)          #当层的局部变量没有,往上一层找
        def grandson():
            print('我的爷爷是%s' %auth_type)
        grandson()
    print(locals())       #打印当前层的局部变量  {'son': <function father.<locals>.son at 0x00000000022788C8>, 'auth_type': 'filedb'}
    son()
father('filedb')
输出
{'son': <function father.<locals>.son at 0x00000000028F88C8>, 'auth_type': 'filedb'}
我的爸爸是linhaifeng_1
我的爷爷是filedb

装饰器的实现

import time
def timmer(func): #func=test
    def wrapper():
        # print(func)
        start_time=time.time()
        func() #就是在运行test()
        stop_time = time.time()
        print('运行时间是%s' %(stop_time-start_time))
    return wrapper

@timmer #test=timmer(test)
def test():
    time.sleep(3)
    print('test函数运行完毕')
test()

# res=timmer(test)  #返回的是wrapper的地址
# res()  #执行的是wrapper()

# test=timmer(test)  #返回的是wrapper的地址
# test()  #执行的是wrapper()

#  @timmer  就相当于 test=timmer(test)

装饰器的预演

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time = time.time()
        print('函数运行时间是%s' %(stop_time-start_time))
        return res
    return wrapper
加上返回值
import time
def timmer(func): #func=test
    def wrapper():
        start_time=time.time()
        res=func() #就是在运行test()
        stop_time = time.time()
        print('运行时间是%s' %(stop_time-start_time))
        return res  #func的返回值
    return wrapper

@timmer #test=timmer(test)
def test():
    time.sleep(3)
    print('test函数运行完毕')
    return '这是test的返回值'

res=test()  #就是在运行wrapper
print(res)
 

加上参数

#这里变化还是一步步的变化
import time
def timmer(func): #func=test1
    def wrapper(*args,**kwargs): #test('linhaifeng',age=18)  args=('linhaifeng')  kwargs={'age':18}
        start_time=time.time()
        res=func(*args,**kwargs) #就是在运行test()         func(*('linhaifeng'),**{'age':18})
        stop_time = time.time()
        print('运行时间是%s' %(stop_time-start_time))
        return res
    return wrapper

@timmer #test=timmer(test)
def test(name,age):
    time.sleep(3)
    print('test函数运行完毕,名字是【%s】 年龄是【%s】' %(name,age))
    return '这是test的返回值'

@timmer
def test1(name,age,gender):
    time.sleep(1)
    print('test1函数运行完毕,名字是【%s】 年龄是【%s】 性别【%s】' %(name,age,gender))
    return '这是test的返回值'

res=test('linhaifeng',age=18)  #就是在运行wrapper
print(res)
#
test函数运行完毕,名字是【linhaifeng】 年龄是【18】
运行时间是3.0040435791015625
这是test的返回值       #运是test的返回值,为什么啊

test1('alex',18,'male')# 这几个值都是给了args
test1函数运行完毕,名字是【alex】 年龄是【18】 性别【male】



def test2(name,age,gender): #test2(*('alex',18,'male','x','y'),**{})
    #name,age,gender=('alex',18,'male','x','y')
    print(name)
    print(age)
    print(gender)
#
def test1(*args,**kwargs):
    test2(*args,**kwargs)  #args=('alex',18,'male','x','y') kwargs={}

# test2('alex',18,gender='male')

test1('alex',18,'male')
解压序列
a,b,c =(1,2,3)
l=[1,2,3,5,6,8,9,5,8,6,8]
a,*_,c=l
print(a,c,_)   #1 8 [2, 3, 5, 6, 8, 9, 5, 8, 6] 取l第一个和最后一个  中间的放给 _
a,b,*m,c,d=l
print(a,b,m,c,d)    #  1 2 [3, 5, 6, 8, 9, 5, 8] 6 8

带登录验证功能的装饰器

 
这里是无参数的装饰器 这章节较晕,可以debug看看
user_list=[
    {'name':'alex','passwd':'123'},
    {'name':'linhaifeng','passwd':'123'},
    {'name':'wupeiqi','passwd':'123'},
    {'name':'yuanhao','passwd':'123'},
]  #如果账户密码是在文件里边,可以用之前学的提取文件内容的方式,要注意文件内的都是字符串,要用eval函数转换成对应的字典或者其他形式
current_dic={'username':None,'login':False}    #判断是否已经登录过了 ,下边执行函数不用重复登录


def auth_func(func):  #这一层是认证类型,可能对于不同的函数要用的认证类型不一样
    def wrapper(*args,**kwargs):
        if current_dic['username'] and current_dic['login']:  #如果有用户名,已经登录,则直接运行,不用再登录了
            res = func(*args, **kwargs)
            return res
        username=input('用户名:').strip()   #否则输入用户名和密码
        passwd=input('密码:').strip()
        for user_dic in user_list:     #判断用户名和密码是否在user_list内,历遍数据是否对应上
            if username == user_dic['name'] and passwd == user_dic['passwd']: #如果用户名和密码都正确了
                current_dic['username']=username  #把登录用户和是否登录的状态也改掉
                current_dic['login']=True
                res = func(*args, **kwargs)     #执行输入函数
                return res
        else:   #else位置与for相对,整个for循环都没有找到对应的用户名和密码,for内找到的话return就已经停止了,对输出无影响
            print('用户名或者密码错误')
            print(current_dic['login'])
            #这里不应该是赋值给current_dic['login']=False 吗,不然如果上一次登录成功会导致一直是True
            #****但是注意这里的current_dic['login']是局部变量,不能影响全局变量内,只能在这个函数内改变,但是不能改变全局变量的current_dic['login']

    return wrapper

@auth_func
def index():
    print('欢迎来到京东主页')

@auth_func
def home(name):
    print('欢迎回家%s' %name)

@auth_func
def shopping_car(name):
    print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))

print('before-->',current_dic)
index()
print('after--->',current_dic)

home('产品经理')

输出
before--> {'username': None, 'login': False}
用户名:alex     #先登录
密码:123
欢迎来到京东主页   #验证了已经是登录状态,和正确登录,运行函数
after---> {'username': 'alex', 'login': True}
欢迎回家产品经理     #执行home函数

# shopping_car('产品经理')

带参数有验证功能的装饰器

user_list=[
    {'name':'alex','passwd':'123'},
    {'name':'linhaifeng','passwd':'123'},
    {'name':'wupeiqi','passwd':'123'},
    {'name':'yuanhao','passwd':'123'},
]
current_dic={'username':None,'login':False}

def auth(auth_type='filedb'):       #多加一个参数
    def auth_func(func):
        def wrapper(*args,**kwargs):
            print('认证类型是',auth_type)
            if auth_type == 'filedb':
                if current_dic['username'] and current_dic['login']:
                    res = func(*args, **kwargs)
                    return res
                username=input('用户名:').strip()
                passwd=input('密码:').strip()
                for user_dic in user_list:
                    if username == user_dic['name'] and passwd == user_dic['passwd']:
                        current_dic['username']=username
                        current_dic['login']=True
                        res = func(*args, **kwargs)
                        return res
                else:
                    print('用户名或者密码错误')
            elif auth_type == 'ldap':
                print('鬼才特么会玩')
                res = func(*args, **kwargs)
                return res
            else:
                print('鬼才知道你用的什么认证方式')
                res = func(*args, **kwargs)
                return res

        return wrapper
    return auth_func

@auth(auth_type='filedb') #auth_func=auth(auth_type='filedb')-->@auth_func 附加了一个auth_type  --->index=auth_func(index)
def index():
    print('欢迎来到京东主页')

@auth(auth_type='ldap')
def home(name):
    print('欢迎回家%s' %name)
#
@auth(auth_type='sssssss')
def shopping_car(name):
    print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))

print('before-->',current_dic)
index()
print('after--->',current_dic)
home('产品经理')
输出
before--> {'username': None, 'login': False}
认证类型是 filedb
用户名:alex
密码:123
欢迎来到京东主页
after---> {'username': 'alex', 'login': True}
认证类型是 ldap
鬼才特么会玩
欢迎回家产品经理

# shopping_car('产品经理')

猜你喜欢

转载自blog.csdn.net/yunyupianlan/article/details/81045615