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

2023-11-15

/**
 * @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循环是要求得到的最终数据 (形态)
'''
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

函数包装修饰:装饰器,迭代器,生成器【Python-5】 的相关文章

随机推荐

  • (一)python库httprunner4 用法

    4个命令 httprunner V httprunner h hrun xxx 运行yaml json pytest 会内部执行hmake hmake xxx 把yaml json格式转成pytest测试用例 一个yaml用例结构 由一个c
  • 服务器查看系统盘位置,云服务器ecs怎么查看系统盘

    云服务器ecs怎么查看系统盘 内容精选 换一换 本节介绍将Windows操作系统的KVM实例变更为擎天架构实例的操作步骤 KVM实例 参考规格清单 查询对应规格的虚拟化类型 擎天架构实例 选择 通用计算增强型C7 变更规格时不支持修改网络类
  • 小样本目标检测综述 --刘浩宇,王向军 --阅读笔记

    文章目录 1 基本背景 2 大样本与小样本的对比 3 在没有大量数据支持的情况下 小样本检测保证检测效果 有哪些解决方法 3 1 数据域 3 1 1 转化原有数据集 D t D t
  • Intel编译器的强大pragma:unroll_and_jam()/nounroll_and_jam()

    Intel官方文档 Hints to the compiler to enable or disable loop unrolling and jamming These pragmas can only be applied to ite
  • Vim快速移动光标至行首和行尾 、第一行和最后一行

    vi中跳到文件的第一行和最后一行 由于vi编辑器不能使用鼠标 所以一个大文件如果要到最后一行只用键盘下键的话会是一个很痛苦的过程 还好有各种比较快捷的方法归我们使用 1 vi 编辑器中跳到文件的第一行 a 输入 0 或者 1 回车 b 键盘
  • 如何一次性选中WORD文档中的所有表格

    1 将下面的脚本复制 Sub SelectAllTables Dim tempTable As Table Application ScreenUpdating False 判断文档是否被保护 If ActiveDocument Prote
  • B-S模式API数据传输方案

    随着面向服务技术架构的兴起 越来越多的应用系统开始进行分布式设计和部署 系统由原来的单一的技术架构变成了面向服务的多系统架构 原来在一个系统之间就可以完成的业务流程 现在要通过多系统之间的多次交互实现 那么面向服务的多系统架构之间必然有着大
  • 【openwrt】【编译问题】openwrt编译问题

    undefined reference to pthread once 在某次openwrt编译过程中出现了undefined reference to pthread once错误 具体报错信息如下 openwrt staging dir
  • 备战蓝桥杯day2

    23 01 07 蓝桥杯day2 CH2 杂题 一 填空题 所谓杂题是指没有明确的解题算法 通过思考寻找最简单的解题路径 解题方式包括但不限于手算 编程 excel和简单的python程序 对于一些填空题 手算有时候更加方便快捷 当然手快选
  • 虹膜识别论文5:DeepIrisNet2 2019年 学习心得

    DeepIrisNet2 Learning Deep IrisCodes from Scratch for Segmentation Robust Visible Wavelength and Near Infrared Iris Reco
  • mybatis常用sql汇总

    select sum case when ismm smm type 1 and ismm smm status 0 then ismm smm num else 0 end as monthPurchaseNum sum case whe
  • Dockerfile构建SSH、Systemctl、Nginx、Tomcat、MySQL镜像实验

    目录 一 构建SSH镜像 二 构建Systemctl镜像 三 构建Nginx镜像 四 构建Tomcat镜像 五 构建MySQL镜像 一 构建SSH镜像 1 创建镜像目录方便管理 mkdir opt sshd cd opt sshd 2 创建
  • Vue3注册全局指令

    在src目录下新建directives permission js文件 export default name action mounted el binding vnode console log vnode ctx vonde debu
  • 当我们在讨论设备像素比(device pixel ratio,dpr)的时候我们在讨论什么?

    目录 0 为什么要写这篇文章 1 设备像素比的问题在哪里 1 1 不同的论述导致不同的理解 1 2 设备独立像素与CSS像素 1 3 小结 2 设备像素比 设备物理像素 CSS像素 真的正确吗 2 1 PC端验证 2 2 手机端验证 2 3
  • Uniapp使用腾讯地图并进行标点创建和设置保姆教程

    使用Uniapp内置地图 首先我们需要创建一个uniapp项目 首先我们需要创建一个uniapp项目 我们在HBuilder左上角点击文件新建创建一个项目 然后下面这张图的话就是uniapp创建项目过程当中需要注意的一些点和具体的操作 然后
  • VBA SPLIT函数详解

    VBA编程是经常会用到字符串拆分函数SPLIT 用法也不复杂 但是大家对于这个函数的参数未必完全了解 下面结合示例讲解一下参数的用法 SPLIT函数的语法格式如下 Split expression delimiter limit compa
  • QCC512x/302x笔记(0)-- 调试笔记索引

    博文索引 QCC512x 302x笔记 1 qcc5124芯片开发入门 QCC512x 302x笔记 2 usb驱动安装和烧录指引 QCC512x 302x笔记 3 只改一行代码 实现串口输出调试log 作者有话说 哈喽大家好 我是书哥Su
  • Java-Map常用子类

    今天讲解Map常用的子类 HashMap LinkedHashMap以及TreeMap 文章目录 一 HashMap 1 介绍 2 注意 二 LinkedHashMap 三 TreeMap 1 介绍 2 代码演示 一 HashMap 1 介
  • NEO-M8N模块设置参数输出

    NEO M8N模块设置参数输出 需求 1 软件要求 NEOM8N要求软件吧按本是u center8 20 这之下的版本可能会设置不成功 2 设置GPS输出格式 近期有个需求 解析GPS输出 我只需要经纬度信息 输出信息一般都比较多 所以需要
  • 函数包装修饰:装饰器,迭代器,生成器【Python-5】

    file author jUicE g2R qq 3406291309 彬 bin 必应 一个某双流一大学通信与信息专业大一在读的技术彩笔 brief python小白入门笔记 copyright 2022 8 COPYRIGHT 原创技术