迭代器、生成器、装饰器(闭包)、解压序列

一.迭代器
1.迭代器协议
迭代器协议:对象必须提供一个next方法,执行该方法要么返回一个迭代中的下一项,要么就引起一个Stopiteration异常,以终止迭代。
可迭代对象:实现了迭代器协议的对象(如何实现:对象都实现一个__iter__方法)
协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(for,sum,max,min等)使用迭代器对象访问对象
2.for循环的本质:循环所有对象,全都是使用迭代器协议
字符串、列表、元素、字典、集合、文件对象,这些都不是可迭代对象,只不过是for循环式,调用了他们内部的__iter__方法,把它们变成了可迭代对象,然后for循环可迭代对象的__next__方法去取值,而用for循环会捕捉异常,以终止迭代。

x='hello'
iter_test=x.__iter__()
print(iter_test)
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
<str_iterator object at 0x000001BD4502D320>
h
e
l
l
o
print(iter_test.__next__())
Traceback (most recent call last):
  File "D:/python-code/bilibili小甲鱼从0学python/lianxi.py", line 9, in <module>
    print(iter_test.__next__())
StopIteration

集合的遍历与迭代方法

s={1,2,3}
for i in s:
    print(i)
iter_s=s.__iter__()
print(iter_s)
print(iter_s.__next__())
print(iter_s.__next__())
print(iter_s.__next__())
1
2
3
<set_iterator object at 0x000001A14BCD6D80>
1
2
3

字典与文件

 dic={'a':1,'b':2}
 iter_d=dic.__iter__()
 print(iter_d.__next__())
f=open('test.txt','r+')
iter_f=f.__iter__()
print(iter_f)
print(iter_f.__next__(),end='')
print(iter_f.__next__(),end='')

print(next(iter_1))=print(iter_1.next())#next方法
迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
迭代器优缺点:
#优点:

  • 提供一种统一的、不依赖于索引的迭代方式
  • 惰性计算,节省内存
    #缺点:
  • 无法获取长度(只有在next完毕才知道到底有几个值)
  • 一次性的,只能往后走,不能往前退

二.生成器
1.什么是生成器
一种数据类型,这种数据类型自动实现了迭代器协议(其他数据类型需要调用自己内置的iter方法),所以生成器就是可迭代对象
2.生成器分类及其表现形式
生成器函数:常规函数定义,但是使用yield语句而不是return语句返回结果,yield语句每次只返回一个结果,在每个结果中间,挂起函数的状态,以便下次从他离开的地方继续执行,对比return,可以返回多次值,可以挂起/保存函数的运行状态

def test():
    yield 1
    yield 2
    yield 3
g=test()
print('来自函数',g)
print(g.__next__())
print(g.__next__())

生成器表达式:类似于列表的推导,但是生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

name='alex'
res='SB' if name == 'alex' else '帅哥'#三元表达式
print(res)
#列表解析
egg_list=[]
for i in range(10):
     egg_list.append('鸡蛋%s' %i)
print(egg_list)
l=['鸡蛋%s' %i for i in range(10)]
l1=['鸡蛋%s' %i for i in range(10) if i > 5 ]
l1=['鸡蛋%s' %i for i in range(10) if i > 5 else i] #没有四元表达式
l2=['鸡蛋%s' %i for i in range(10) if i < 5] 
-------------------------------------------------------------------------
laomuji=('鸡蛋%s' %i for i in range(10)) #生成器表达式
print(laomuji)
print(laomuji.__next__()) 
print(laomuji.__next__())
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))

3.生成器优点
对延迟操作提供支持,所谓延迟操作,指在需要的时候产生结果,而不是立刻产生结果,这也是生成器的主要好处,同时也节省内存,效率高
三.装饰器
1.什么是装饰器
本质是一个函数,功能是为其他函数添加附加功能
原则:
不修改被修饰函数的源代码
不修改被修饰函数的调用方式
装饰器的目标:在遵循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

但是如何在不违背原则下实现这个功能呢,以下代码即是装饰器的预演
#解压序列

>>> a=(1,2,3,4,5,6)
>>> x,y,z=(1,2,3)#解压序列一一对应
>>> x,*_,y=a#取序列的第一个和最后一个值
>>> x
1
>>> y
6
>>> x=1
>>> y=2
>>> x,y=y,x#两个变量交换数值的简便方法
>>> x
2
>>> y
1
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
-----------------------------------------------
    @timmer#调用上面的装饰器,  @timmer  就相当于 test=timmer(test)
def test():
    time.sleep(3)
    print('test函数运行完毕')
test()
# res=timmer(test)  #返回的是wrapper的地址
# res()  #执行的是wrapper()
#res改成test就实现不改变test函数的调用方式
# test=timmer(test)  #返回的是wrapper的地址
# test()  #执行的是wrapper()
#  @timmer  就相当于 test=timmer(test)

高阶函数
高阶函数定义:
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
3.满足上述条件任意一个,都可称之为高阶函数
实现foo函数运行的时间功能,但这样修改了函数的调用方式,不符合装饰器

import time
def foo():
    time.sleep(3)
    print('你好啊林师傅')
def test(func):
    print(func)
    start_time=time.time()
    func()
    stop_time = time.time()
    print('函数运行时间是  %s' % (stop_time-start_time))
foo()
test(foo)#高阶函数

实现foo函数运行的功能,返回值是函数,函数调用方式未修改

def foo():
    print('from the foo')
def test(func):
    return func
res=test(foo)
print(res)
res()
foo=test(foo)
print(res)
foo()

综合以上两种方式来实现装饰器:

import time
def foo():
    time.sleep(3)
    print('来自foo')
def timer(func):
    start_time=time.time()
    func()
    stop_time = time.time()
    print('函数运行时间是  %s' % (stop_time-start_time))
    return func#函数作返回值不修改函数调用方式
foo=timer(foo)
foo()

但是结果多运行了一次

来自foo
函数运行时间是  3.010345935821533
来自foo

所以高阶函数满足不了装饰器的功能,到此为止
函数嵌套
在函数里面再定义一个函数才叫嵌套,在函数里面调用一个函数不叫嵌套

def bar():
    print('from bar')

def foo():
    print('from foo')
    def test():
        pass
def father(name):
    print('from father %s'%name)
    def son():
        print('from the son')
    print(locals())#打印局部变量,此时仍然son()也是局部变量
father('xiaoliangpeng')
》》》from father xiaoliangpeng
》》》{'son': <function father.<locals>.son at 0x000001B97C351AE8>, 'name': 'xiaoliangpeng'}

闭包

def funX(x):
    def funY(y):
        return x*y
    return funY

如果在一个内部函数,funY(y)就是这个内部函数,对在外部作用域(但不是在全局作用域)的变量进行引用;x就是被引用的变量,x在外部作用域funX里面,则这个内部函数funY就是闭包。

def counter():
    n = 0
    def incr():
        nonlocal n
        x = n
        n += 1
        return x
    return incr
c = counter()
print(c())
print(c())
print(c())
print(c.__closure__[0].cell_contents) #查看闭包的元素
0
1
2
3

闭包=函数块+定义函数时的环境,funY是函数块,x是环境,环境可以有很多,不止x一个
内部函数包含对外部作用域而非全局作用域的引用
闭包的意义:
返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
闭包的用途:
#闭包主要是在函数式开发过程中使用。以下介绍两种闭包主要的用途
#用途1,当闭包执行完后,仍然能够保持住当前的运行环境。
#闭包可以根据外部作用域的局部变量来得到不同的结果,这有点像一种类似配置功能的作用,我们可以修改外部的变量,闭包根据这个变量展现出不同的功能。比如有时我们需要对某些文件的特殊行进行分析,先要提取出这些特殊行
应用领域:
延迟计算(原来我们是传参,现在我们是包起来)
装饰器功能验证

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_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:
            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('用户名或者密码错误')

    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('产品经理')

带参数验证功能装饰器

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('产品经理')
shopping_car('产品经理')
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值