函数包装修饰:装饰器,迭代器,生成器【Python-5】

本文详细介绍了Python编程中的闭包概念,包括其特点和应用,如变量常驻内存和保护变量。接着,文章深入讨论了装饰器,解释了装饰器的本质是闭包,并展示了如何使用装饰器来扩展函数功能,同时处理装饰器的参数和返回值问题。此外,还探讨了迭代器和生成器,强调它们在内存管理和效率上的优势,并给出了实战示例。最后,提到了匿名函数(lambda表达式)及其在Python中的应用。
摘要由CSDN通过智能技术生成
/**
 * @file            
 * @author          jUicE_g2R(qq:3406291309)————彬(bin-必应)
 *						一个某双流一大学通信与信息专业大一在读的技术彩笔	
 * 
 * @brief           python小白入门笔记
 * 
 * @copyright       2022.8
 * @COPYRIGHT			 原创技术笔记:转载需获得博主本人同意,且需标明转载源
 *
 * @language        python
 * @Version         1.0还在学习中  
 */
#27
#                                                      #闭包
'''本质: 内层函数对'''
"""特点:
    1.可以使得一个变量常驻于内存
    应用:计数器
    
    2.保护变量不被修改(全局变量易被修改)
    引入:
    a=10
    a=20
    a=30最后print出来是30  (只会打印最终值)
"""
def func():
    a=10
    def inner():            #闭包部分@
        print(a)              #@
        return  a           #@
    return inner          #@

ret=func()
ret()
'''
a=10被inner使用,inner被外层函数func函数作为返回值进行返回
'''
#ret(即inner)=>什么时候被执行
#可能立马ret()执行,或数行代码后编写ret()执行
'''应用原理:使得inner里的变量常驻于内存'''

#仿计数器制作
'''写法一:在全局调用局部执行'''
def func():
    a=0                       #设置初始量为0
    def inner():
        nonlocal a
        a+=1
        print(a)
        return a
    return inner
ret=func()
ret()
'''写法二:返回到全局,在全局print'''
def func():
    a=0                       #设置初始量为0
    def inner():
        nonlocal a
        a+=1
        return a
    return inner
ret=func()
r1=ret()                     #计数第一次
r2=ret()                     #计数第二次
print(r1,r2)


'''应用:
利于编写出更安全的程序'''



#28
#                                                    #装饰器
'''(结论很关键,推导过程难可略过)'''
#装饰器: 本质上就是一个闭包
'''可以在不改变原有函数调用的情况下,
给函数增加新的功能'''
#即:可在函数前后添加新功能,但不用改原来程序


#引子:
'''相关知识回顾:
    1.函数可以做为参数进行传递
    { func(inner) 表示传递inner函数本身
    inner() 表示传递inner执行后的程序 }
    
    2.函数可以作为返回值返回
    
    3.函数名称可以当成变量一样进行赋值操作 
'''
#1  函数可以做为参数进行传递
def func():
    print("我是func")
def g(fn):
    fn()                                  #fn()即func()
g(func)

'''调用g,传递func函数,fn=func
fu()发出执行指令,执行func中的print任务'''


#2  函数可以作为返回值返回
def func():
    def inner():
        print(123)
    return inner
i=func()
i()                           #调用func后执行inner

#worry:
def func():
    def inner():
        print(123)
    return inner
i=func()
print(i)                    #打印返回值inner内存地址

#详看>15.1

#3  函数名称可以当成变量一样进行赋值操作
def func1():
    print("i am func1")
def func2():
    print("i am func2")
func1=func2
func1()                               #执行func2里的程序



#28.1              装饰器雏形
#模拟管家操控外挂
'''对两功能函数封装新功能'''
def guard(game):        #管家负责外挂的开启与关闭
   def inner():             #对inner进行闭包封装@
        print("开启外挂") #@
        game()               #@
        print("关闭外挂") #@
   return inner           #将inner函数返回给了guard函数@

@guard                         #艾特guard注意此函数的特殊性
def play_dnf():              #相当于执行了play_dnf=guard(play_dnf)
    print("DNF运行")
@guard
def play_lol():
    print("LOL运行")

play_dnf=guard(play_dnf)     #重新定义pl_
# '''pl_得到的赋值来自于guard的返回值->来自于inner的返回值'''
play_dnf()                   #实际上运行的是inner函数
play_lol()


'''应用:
用户登录时,日志
(便于后续的修改,且安全保护以前的数据不被篡改)'''

#雏形模板
'''
def wrapper(fn):            #wrapper:装饰器,fn: 目标函数
    def inner():
        ( print(1) )             #目标函数执行前(检查用户登录情况)
        fn()                       #调用inner函数执行 
        ( print(2) )             #目标函数执行后(日志)
    return inner             # 返回函数,非函数执行结果

'''


#28.2               被装饰函数的参数问题
def guard(game):
    def inner(user_name,password):         #接收相关参数
        game(user_name,password)            #按需接收参数并运行
    return inner
@guard
def play_lol(user_name,password):
    print("开始游戏")
    print("user_name:",user_name)
    print("password:",password)

play_lol("admin","123")   #调用时,提供给inner相关参数的值


#如果多个功能参数要求不同数目的
#solution:
"""inner添加参数<args得到是一个元组,kwargs得到是一个字典>"""
def guard(game):
    def inner(*args,**kwarge): # *表示接收所有参数,打包成元组和字典
        game(*args,**kwarge) # *把元组和字典打散成位置与关键字参数传递进去
    return inner
'''注: 打散后都是参数,不再存在外壳括号,否则不能对'''
@guard
def play1(user_name,password):
    print("开始游戏")
    print("user_name:",user_name)
    print("password:",password)
@guard
def play2(user_name, password,hero):
    print("user_name:", user_name)
    print("password:", password)
    print("hero:",hero)

play1("ntzjake","1")
play2("joker","2","jake")

'''易错点:尤其要注意game()运行的那一行注释*******************
是个特例'''

'''优化:
def guard(fn):
    def inner(*args,**args):
        fn(*args,**args)
        ...
'''



#28.3                     装饰器的返回问题
def guard(game):
    def inner(*args,**kwarge):
        ret=game(*args,**kwarge)
        '''这里是目标函数的执行,这里能够拿到从目标函数返回的返回值'''
        #solution:
        return ret
        '''给inner返回返回值, 该返回值来自game的调用,
        即调用被装饰函数play1,获得play1的返回值,并赋值给ret,
        将play1的返回值返回给inner,再由inner返回给guard'''
    return inner

@guard
def play1(user_name,password):
    print("开始游戏")
    print("user_name:",user_name)
    print("password:",password)
    return "一把屠龙刀"

ret=play1("ntzjake","1")   #加了@的play1实际调用的是inner函数
print(ret)                         #所以由于inner内部没有return返回返回值,print出None



'''再优化:'''
#通用装饰器的模板
'''
def wrapper(fn):                  #fn实际调用的是target函数
    def inner(*args,**kwargs):
        (函数执行前干......)
        ret= fn(*args,**kwargs)    #实际调用的是target
        (函数执行后干......)
        return ret
    return inner
@wrapper
def target():
    ...
target() =>实际调用的是inner =>inner()
'''


#28.4  一个函数被多个装饰器装饰
def wrapper1(fn):                  #2^1 fn: wrapper2.inner
    def inner(*args,**kwargs):
        print("there's the@entrance of wrapper@1")     #!1
        ret=fn(*args,**kwargs)                                      #!(2)执行wrapper2的inner
        print("there's the@exit of wrapper@1")            #!10
        return ret                                                       #!(11)
    return inner                                                       #!(12)返回值返给w1

def wrapper2(fn):                  #1^1 fn:target
    def inner(*args,**kwargs):
        print("there's the@entrance of wrapper@2")     #!3
        ret=fn(*args,**kwargs)                                     #!(4)执行target
        print("there's the@exit of wrapper@2")           #!7
        return ret                                                      #!(8)
    return inner                                                      #!(9)返回给wrapper2,
                                                                            #继续执行w1中的i
'''局部不影响全局:内部可为同名局部函数'''

@wrapper1  #把wrapper2与target包装的装饰器再进行装饰
'''2^2 target=target(wrapper2.inner) => taregt:wrapper1.inner'''
'''先从外包装运行而后内包装运行'''
@wrapper2  #1^2 target=wrapper2(target) => target: wrapper2
def target():
    print("i am target")                                            #!5

target()                                                                  #!(6)调用wrapper2的inner,
                                                                            #(继续读取w2的i中的程序).

"""result:there's the@entrance of wrapper@1
              there's the@entrance of wrapper@2
              i am target
              there's the@exit of wrapper@2
              there's the@exit of wrapper@1
              """
#原因解释:
'''就近原则:target函数靠近w2,先被w2所装饰,
包装成一个装饰器后,整体被再修饰'''



'''结论'''
#简要过程: w1>w2>target>w2>w1.



#28.5                       装饰器的实战*********************************************
"""模拟员工注册与销注"""
'''添加,删除,修改,寻找'''
login_flag=False                                    #先默认未完成登录验证

def login_verify(fn):                              #登录账户的验证
    def inner(*args,**kwargs):
        global login_flag                           #使全局变量进入局部
        if login_flag==False:                     #与下面fn()居于同一垂直线
            '''if判断解决了重复登录的问题'''
            print("请继续完成登录操作...")
            # 在此处完成登录操作中的输入:
            while 1:                                        #若一直登录不成功将一直停留在这层
                user_name=input(">>>请输入用户名:")
                password=input(">>>请输入您的密码:")
                #在此处完成登录验证:
                if user_name=="admin" and password=="123456":
                    print("登录成功...")
                    login_flag=True
                    break
                else:
                    print("验证失败...")
                    print("用户名或密码错误>请重新输入")

        ret=fn(*args,**kwargs)                    #实现后续的添加等操作
        return ret
    return inner

@login_verify
def add():
    print("进入添加员工页面中...")
    lst=[]
    while 2:
        a=input("请输入新员工姓名: ")
        button = input("是否结束员工加入操作: (是/否)")
        lst.append(a)
        if button =="是":
            print("正在添加中,请稍后...")
            print("成员名单:",lst)
            break
        elif button=="否" :
            print("请继续输入员工姓名...")
add()

其他同理:
def delete():
    print("进入删除员工页面中...")
    lst=[]
    p=input("输入被删除员工姓名")
    lst.pop(p)
def update():
    print("进入更新(修改)信息页面中...")
    lst=[]
    u = input("输入需要修改员工姓名")
    lst[ ]=u
def search():
    print("进入检索员工页面中...")




#29
#                                                                #迭代器
'''可迭代的数据类型都会提供一个叫迭代器的东西,
这个迭代器可以帮我们把数据类型中的所有数据逐一的拿到'''
#29.1
#引子:
'''
for 变量 in 可迭代:
    pass
'''
for c in "呵呵哒":
    print(c)     #result:呵(/n) 呵(/n) 哒
for c in 123:
    print(c)     #报错: 'int' object is not iterable
'''iterable: 可迭代的
iterator: 迭代器
可迭代的数据类型str, list, tuple, dict, set, open()'''


#关键知识点
'''
A.获取迭代器的两种方案:
    1.iter()内置函数可以直接拿到迭代器(*****)
    2.  .__iter__()特殊方法[注意:双下划线]***************
B.从迭代器中拿到数据:
    1.next()内置函数
        注意:a.一次只拿一个
               b.已经拿完时再次提取会报错: StopIteration       
    2.  .__next__()特殊方法

C.for里面一定要拿迭代器,所以所有不可迭代的东西不能for循环

'''
#A1.
it=iter("呵呵哒")
print(it)                     #得到str的迭代器的内存地址
#A2.替代(不常用)
it="呵呵哒".__iter__()
print(it.__next__())


#模拟for循环工作原理:
s="i am date"
it=s.__iter__()                  #拿到迭代器
while 1:
    date=it.__next__()
    print(date)                  #进行for循环的循环体,最后会报错
# 原因:迭代结束后继续循环会报错

#solution:#试探性循环
'''py中异常处理:'''
s="date"
it=s.__iter__()
while 1:
    try:
        date=it.__next__()
        print(date)
    except StopIteration:     #当报错时马上停止循环
        break
print("完成")


"""
总结:1.迭代器统一了所有不同(可迭代的)数据类型的遍历工作
           2.迭代器本身也是可迭代的
迭代器本身的特性:
    1. 只能向前,不能反复
    2. 特别节省内存(内部存放仿指针)
        极小内存可以处理庞大数据集
    3. 惰性机制
        调用一次运行一次,不自动一次性全部运行完,
        等待下一次调用
"""





#30
#                                                          #生成器
'''
生成器的本质就是迭代器, *************************
    创建生成器的两种方案:
        1.生成器函数
        2.生成器表达式
'''
#30.1         生成器函数
#引子:
def func():
    print(666)
    return 999
ret=func()                     #调用func运行
print(ret)                      #打印出返回值

#关键笔记:
'''
1.          generator: 生成器
2.生成器函数中有一个关键字yield
    只要函数中出现yield,就是一个生成器函数,
        作用:
            A。可以返回数据( 相当于return)
            B。可以分段的执行函数的内容,
            通过__next()__可以执行到下一个yield位置前停止

3.生成器函数执行时, 并不会执行函数, 得到的是生成器

'''
def func():
    print(666)
    yield 999
ret=func()
print(ret)         #<generator object func at 0x00000277662ACD60>


'''基于生成器本质是迭代器的原理:'''
def func():
    print(666)
    yield 999
ret=func()
print(ret.__next__())             #正常地输出print数据和返回值


'''可以分段的执行函数的内容'''
def func():
    print(123)
    return 999
    print(456)                          #return后的同级程序无效
func()
'''但是yield:'''
def func():
    print(123)
    yield 999
    print(456)
    yield 666
ret=func()
print(ret.__next__())                 #注意迭代器惰性特征
print(ret.__next__())


'''生成器的实战项目'''
# 去工厂定制10000件衣服
def order():
    lst=[]
    for i in range(10000):
        lst.append(f"衣服(编号{i})")            #将每件的码随着衣服打出
    return lst                                 #返回lst的最后结果
lst=order()
print(lst)

'''存在的问题:严重浪费内存, 需求<<供给'''
#solution:
def order():
    lst=[]
    for i in range(10000):
        lst.append(f"衣服(编号{i})")
        if len(lst)==10:                       #按需少量取出数据
            yield lst                             #直到10次
            #下一次拿数据将lst清空:
            lst=[]

gen=order()
print(gen.__next__())                     #负责每次拿数据的命令发出
'''注意:1~49,50件'''
print(gen.__next__())                     #第二批次


'''
优势:
用好了,特别节省内存
'''


#30.2         推导式
'''优点:简化代码'''
'''缺点:逻辑不清晰'''
'''语法:
    1.列表推导式: [数据 for循环 (if循环)](两个间有一个空格)
    2.集合推导式:  {数据 for循环 (if循环)}
    
    3.字典推导式: {k,v for循环 (if循环)}
#注意:
1.元组没有推导式
原因:列表,集合,字典都是可以增删改查数据的,但是元组不能
         
2. (数据 for循环 (if判断)) =>不是元组推导式
                                        而是生成器表达式
'''
#源码
lst=[]
for i in range(10):       #程序都是从0开始数的
    lst.append(i)
print(lst)

修改成 列表推导式
lst=[i for i in range(10)]       #其中得到的数据就是i
print(lst)


#              创建奇数的列表1~9
lst=[i for i in range(1,10,2)]
print(lst)

#写法二:
lst=[i for i in range(10) if i % 2==1]
print(lst)
'''结: 利用奇数除二余一的特性作为条件判断'''

#将列表中的英文字母变为大写
lst=["zhang","wang","jake","rose"]
lst1=[item.upper() for item in lst]
'''由此得知:列表中植入的数据应该是期望得到的数据'''
print(lst)


#将列表修改成字典,要求索引作为key, 数据作为value
lst=["潘长江","赵本山","高达","奥特曼"]
dic={i:lst[i] for i in range(len(lst))}
print(dic)
# '''这里的key用i表示,value用lst[i]'''



#30.3         生成器表达式
'''语法:
    (数据 for循环 (if判断))'''
#list(), set(), dict()本身内部存在循环迭代的过程有迭代器
'''list() =>for 循环 =>next()'''
s=list("周杰伦")
print(s)                         #['周', '杰', '伦']






#31
#                                                            #匿名函数
'''就是一个lambda表达式'''
'''语法规则:
    变量= lambda 参数1,参数2...: 返回值
'''
#引子:
def func(a,b):
    return a+b
ret=func()
print(ret)

#改为lambda
fn=lambda a,b:a+b
print(fn)                      #得到的是lambda function
ret=fn(12,13)
print(ret)

'''优势:简洁'''
#常和filter, map一起出现





#32
#                                                       #内置函数的补充(1)
#32.1                                                 #zip
'''把多个可迭代内容进行合并'''

lst1=["赵本山","范伟","苏有朋"]       #姓名
lst2=[60,40,30]                            #年龄
lst3=["卖拐","耳朵大有福","情深雨蒙蒙"]  #作品
#按照位置将其分组放在一起
result=zip(lst1,lst2,lst3)              #相当于for循环,将其先分类
for item in result:                      #对分出来的数据集分开
    print(item)


#32.2                                                   #locals,globals
#locals
'''查看****当前位置****的局部的内容'''
# a=188
# print(locals())
'''locals被写在全局作用域范围内,此时看到的就是全局作用域的内容'''
'''同理: 放在局部作用域,只看得到同级的内容'''


#globals
'''看到的是全局作用域的内容'''





#33
#                                                    #内置函数补充(2)
'''关键笔记:
zip:     可以把多个可迭代的内容合并
sorted:排序
filter:  筛选
map:   映射
'''

#33.1                                              #sorted
'''sort:排序
    格式:
        sorted(__iterable,key,reverse)*****************************
                  ((可迭代的数据类型)数据,排序排序方法,是否翻转)
'''
lst=[123,4,56,7.8]
s=sorted(lst, reverse=False)     #升序排列可以不写reverse翻转
print(s)


#非数字的排列
lst=["瑞秋","牛魔王","简"]
def func(item): #func负责接收item参数, item就是列表中的每一项数据
    return len(item)                               #依据字符长短决定排列顺序

s=sorted(lst,key=func,reverse=False)
print(s)

'''fn 作为排序函数, 对字符进行数字化处理,
按照处理后得到的数据排序'''



#33.2                                               #filter
'''筛选
    格式:
        filter(__function,__iterable)******************************
'''
#筛选出姓张的人
lst=["张无忌","张三丰","张雪莉","唐家三少","王大爷"]
f=filter(lambda x:x.startswith("张"),lst)
print(list(f))
#反筛选
f1=filter(lambda x:not x.startswith("张"),lst)
print(list(f1))




#33.3                                               #map
"""映射"""
#平方口诀表
lst=[1,2,3,4,5,6,7,8,9]
result=[item*item for item in lst]
print(result)
#换做映射处理:
r=map(lambda x:x*x,lst)
print(list(r))

'''应用:
数据分析批量处理'''




'''区别:filter与map在匿名函数处理
x=xxx(lambad x : ...,__iterable)
filter: ...处进行for循环是判断参数是否传入
map:  ...处进行for循环是要求得到的最终数据 (形态)
'''
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值