迭代器、生成器、装饰器

一、迭代器

1、迭代器协议

  1. 迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代的下一项,要么就引起一个StopIteration异常,以终止迭代(只能往后走,不能往前走);
  2. 可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)(可迭代对象指的是内置有__iter__方法的对象);
  3. 协议是一种约定,可迭代对象实现了迭代器协议,Python的内部工具(如for循环,map,sum,max,min函数等)使用迭代器协议访问对象。
  4.  1 1、什么是迭代器对象?
     2 可迭代对象执行obj.__iter__()得到的结果就是迭代器对象
     3 而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象
     4 
     5 文件类型是迭代器对象
     6 open('a.txt').__iter__()
     7 open('a.txt').__next__()
     8 
     9 
    10 2、注意:
    11 迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
    1)可迭代对象包含迭代器。
    2)如果一个对象拥有__iter__方法,其是可迭代对象;如果一个对象拥有next方法,其是迭代器。
    3)定义可迭代对象,必须实现__iter__方法;定义迭代器,必须实现__iter__和next方法。

2、迭代器对象的使用:

dic={'a':1,'b':2,'c':3}
iter_dic=dic.__iter__() #得到迭代器对象,迭代器对象即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身
iter_dic.__iter__() is iter_dic #True

print(iter_dic.__next__()) #等同于next(iter_dic)
print(iter_dic.__next__()) #等同于next(iter_dic)
print(iter_dic.__next__()) #等同于next(iter_dic)
# print(iter_dic.__next__()) #抛出异常StopIteration,或者说结束标志

#有了迭代器,我们就可以不依赖索引迭代取值了
iter_dic=dic.__iter__()
while 1:
    try:
        k=next(iter_dic)
        print(dic[k])
    except StopIteration:
        break
        
#这么写太丑陋了,需要我们自己捕捉异常,控制next,python这么牛逼,能不能帮我解决呢?能,请看for循环

3、Python中的for循环机制

for循环的本质:循环所有对象,全部使用迭代器协议

# l=[1,2,3]
# for i in l:  #i_l=l.__iter_()  i_l.__next__()
#     print(i)

# index=0
# while index < len(l):
#     print(l[index])
#     index+=1


# iter_l=l.__iter__() #遵循迭代器协议,生成可迭代对象
# print(iter_l.__next__())
# print(iter_l.__next__())
#
# for i in l:
#     print(i)

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__())
# print(iter_s.__next__())

# dic={'a':1,'b':2}
# iter_d=dic.__iter__()
# print(iter_d.__next__())

# f=open('test.txt','r+')
# # for i in f:
# iter_f=f.__iter__()
# print(iter_f)
# print(iter_f.__next__(),end='')
# print(iter_f.__next__(),end='')
# l=[1,2,3,4,5]
# diedai_l=l.__iter__()
# while True:
#     try:
#         print(diedai_l.__next__())
#     except StopIteration:
#         # print('迭代完毕了,循环终止了')
#         break

l=['die','erzi','sunzi','chongsunzi']

iter_l=l.__iter__()
print(iter_l)
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(next(iter_l)) #next()---->iter_l.__next__()
迭代器的优缺点:
1
#优点: 2 - 提供一种统一的、不依赖于索引的迭代方式 3 - 惰性计算,节省内存 4 #缺点: 5 - 无法获取长度(只有在next完毕才知道到底有几个值) 6 - 一次性的,只能往后走,不能往前退

注意:

l=[1,2,3]

index=0
while index < len(l):
    print(l[index])
    index+=1

#要毛线for循环,要毛线可迭代,要毛线迭代器

     序列类型字符串,列表,元组都有下标,你用上述的方式访问,perfect!但是非序列类型像字典,集合,文件对象,for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了,而且你看到的效果也确实如此,这就是无所不能的for循环,最重要的一点,转化成迭代器,在循环时,同一时刻在内存中只出现一条数据,极大限度的节省了内存~

二、生成器

#三元表达式
# name='alex'
# name='goulognhui'
# 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] #没有四元表达式

print(l)
# print(l1)
# print(l2)

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))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
# print(next(laomuji))

l=[1,2,3,34]
# map(func,l)

# print(sum(l))
# print(sum())
# print(sum(i for i in range(10000000000000)))

 

### 生成器好处
# 例 求出一段文字中每个单词出现的位置
def index_words(text):
    result = []
    if text:
        result.append(0)
    for index,letter in enumerate(text,1):
        if letter == ' ':
            result.append(index)
    return result
print(index_words('alex is da sb'))
不使用生成器
def index_words(text):
    if text:
        yield 0
    for index,letter in enumerate(text,1):
        if letter == ' ':
            yield index

ret = index_words('alex shi da sb')
print(ret.__next__())
print(ret.__next__())
print(ret.__next__())
print(ret.__next__())
使用生成器

好处:1,使用生成器后,代码行数更少;

   2,我们可以清楚的看到代码每次操作,是要返回一个index,少了appends的干扰

 1 def test():
 2     print('===')
 3     yield 666
 4     print('-----')
 5     yield 777
 6 
 7 g_obj = test()
 8 print(test().__next__())   # 注意:每次使用test(),都是生成一个新的生成器,所以每次都是相当于执行第一个next
 9 print(test().__next__())
10 print(test().__next__())
11 print(test().__next__())
有个坑

注意: 生成器只能遍历一次

三、装饰器

一 什么是装饰器

器即函数

装饰即修饰,意指为其他函数添加新功能

装饰器定义:本质就是函数,功能是为其他函数添加新功能

二 装饰器需要遵循的原则

1.不修改被装饰函数的源代码(开放封闭原则)

2.为被装饰函数添加新功能后,不修改被修饰函数的调用方式

三 实现装饰器知识储备

装饰器=高阶函数+函数嵌套+闭包

四 高阶函数

高阶函数定义:
1.函数接收的参数是一个函数名

2.函数的返回值是一个函数名

3.满足上述条件任意一个,都可称之为高阶函数

def foo():
    print('我的函数名作为参数传给高阶函数')
def gao_jie1(func):
    print('我就是高阶函数1,我接收的参数名是%s' %func)
    func()

def gao_jie2(func):
    print('我就是高阶函数2,我的返回值是%s' %func)
    return func

gao_jie1(foo)
gao_jie2(foo)

高阶函数示范
高阶函数
#高阶函数应用1:把函数当做参数传给高阶函数
import time
def foo():
    print('from the foo')

def timmer(func):
    start_time=time.time()
    func()
    stop_time=time.time()
    print('函数%s 运行时间是%s' %(func,stop_time-start_time))
timmer(foo)
#总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式
把函数当做参数传给高阶函数
#高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名
import time
def foo():
    print('from the foo')

def timmer(func):
    start_time=time.time()
    return func
    stop_time=time.time()
    print('函数%s 运行时间是%s' %(func,stop_time-start_time))
foo=timmer(foo)
foo()
#总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能
函数的返回值是函数名
 1 ## 二者糅合在一起
 2 # import time
 3 # def foo():
 4 #     time.sleep(2)
 5 #     print('from foo')
 6 # def timer(func):
 7 #     start_time = time.time()
 8 #     func()
 9 #     stop_time = time.time()
10 #     print('函数的运行时间为%s'%(stop_time - start_time))
11 #     return func
12 # foo = timer(foo)
13 # foo()
14  ### 结果
15 #  from foo
16 # 函数的运行时间为2.0001142024993896
17 # from foo
18 ## 不合理,函数多运行了一次
参数 和 返回值柔和

1.函数接收的参数是一个函数名
  作用:在不修改函数源代码的前提下,为函数添加新功能,
  不足:会改变函数的调用方式
2.函数的返回值是一个函数名
  作用:不修改函数的调用方式
  不足:不能添加新功能

五 函数嵌套

 1 def father(name):
 2     print('from father %s' %name)
 3     def son():
 4         print('from son')
 5         def grandson():
 6             print('from grandson')
 7         grandson()
 8     son()
 9 
10 father('苟陇辉')

六 闭包

 1 '''
 2 闭包:在一个作用域里放入定义变量,相当于打了一个包
 3 '''
 4 def father(name):
 5     def son():
 6         # name='alex'
 7         print('我爸爸是 [%s]' %name)
 8         def grandson():
 9             # name='wupeiqi'
10             print('我爷爷是 [%s]' %name)
11         grandson()
12     son()
13 
14 father('苟陇辉')
1 函数闭包:
2         内层函数对外层函数非全局变量的引用就叫闭包
3         闭包特性:如果函数闭包,那么该变量在内存中,不会随着函数运行完成,而被释放掉,可重复使用
4         判断是不是闭包  双下滑线 closure方法去测:①:如果返回cell开头就是闭包函数
5                                       ②:如果返回None,就不是
6         闭包的应用:爬虫
7                         可对一次爬取的数据多次使用,开多线程时,都使用第一爬取的数据,不用每个线程都去爬,如果爬的数据有2G,那么一次开10个线程去爬,需要20G内存,太浪费内存,有了闭包之后,10个线程,都使用这一个数据,大大节省了内存
 1 def foo():
 2     name = 'LaoGuAnTou'
 3     def bar():
 4         print(name)
 5     bar()
 6     print(bar.__closure__)  # (<cell at 0x0000024ACE417648: str object at 0x0000024ACE3E2470>,)
 7 foo()
 8 
 9 
10 def test(x):  # 注意这个也是,传入X,相当于在函数里面定义了一个x = 'name',所以是闭包
11     def inner():
12         print(x)
13     inner()
14     print(inner.__closure__)  # (<cell at 0x000002566DDC7648: str object at 0x000002566DE5DDC0>,)
15 
16 name1 = 'gou'
17 test(name1)
18 
19 
20 name2 = 'gou long hui'
21 def test2():
22     global name2
23     name2 = 'laoguantou'
24     def inner():
25         print(name2)
26     inner()
27     print(inner.__closure__)  # None
28 
29 
30 test2()
验证函数是否闭包

七 无参装饰器

无参装饰器=高级函数+函数嵌套

基本框架

1 #这就是一个实现一个装饰器最基本的架子
2 def timer(func):
3     def wrapper():
4         func()
5     return wrapper

加上参数

1 def timer(func):
2     def wrapper(*args,**kwargs):
3         func(*args,**kwargs)
4     return wrapper

加上功能

1 import time
2 def timer(func):
3     def wrapper(*args,**kwargs):
4         start_time=time.time()
5         func(*args,**kwargs)
6         stop_time=time.time()
7         print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time))
8     return wrapper

加上返回值

1 import time
2 def timer(func):
3     def wrapper(*args,**kwargs):
4         start_time=time.time()
5         res=func(*args,**kwargs)
6         stop_time=time.time()
7         print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time))
8         return res
9     return wrapper

使用装饰器

1 def cal(array):
2     res=0
3     for i in array:
4         res+=i
5     return res
6 
7 cal=timer(cal)
8 cal(range(10))

语法糖@

1 @timer  #@timer就等同于cal=timer(cal)
2 def cal(array):
3     res=0
4     for i in array:
5         res+=i
6     return res
7 
8 cal(range(10))

八 装饰器应用示例

use_list = [
    {'name':'goulonghui','passwd':'123'},
    {'name':'alex','passwd':'123'},
    {'name':'wucen','passwd':'123'}
]
current_dic = {'user_name':None,'login':False}
def auth_func(func):
    def wapper(*args,**kwargs):
        if current_dic['user_name'] and current_dic['login']:   ### 如果二者皆为True,表示当前由用户登录,直接执行函数
            res = func(*args, **kwargs)
            return res
        user_name = input('用户名是:').strip()
        passwd = input('密码是:').strip()
        for use_dict in use_list:       ### 去遍历用户列表,对比用户输入的用户名和对应的密码是否存在
            if user_name == use_dict['name'] and passwd == use_dict['passwd']:
                current_dic['user_name'] = user_name    ### 如果存在,则改变开始判断的状态(即改变current_dic = {})
                current_dic['login'] = True
                res = func(*args, **kwargs)
                return res
        else:
            print('用户名或密码错误')
    return wapper


@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,'棉衣','裤子','小吃'))

index()
home('苟陇辉')
shopping_car('苟陇辉')
无参装饰器
 1 ###  给装饰函数传参(闭包,在最外层传)
 2 use_list = [
 3     {'name':'goulonghui','passwd':'123'},
 4     {'name':'alex','passwd':'123'},
 5     {'name':'wucen','passwd':'123'}
 6 ]
 7 current_dic = {'user_name':None,'login':False}
 8 def auth(auth_type = 'filedb'):
 9     def auth_func(func):
10         def wapper(*args,**kwargs):
11             print('使用的类型是%s'%auth_type)
12             if auth_type == 'filedb':
13                 if current_dic['user_name'] and current_dic['login']:   ### 如果二者皆为True,表示当前由用户登录,直接执行函数
14                     res = func(*args, **kwargs)
15                     return res
16                 user_name = input('用户名是:').strip()
17                 passwd = input('密码是:').strip()
18                 for use_dict in use_list:       ### 去遍历用户列表,对比用户输入的用户名和对应的密码是否存在
19                     if user_name == use_dict['name'] and passwd == use_dict['passwd']:
20                         current_dic['user_name'] = user_name    ### 如果存在,则改变开始判断的状态(即改变current_dic = {})
21                         current_dic['login'] = True
22                         res = func(*args, **kwargs)
23                         return res
24                 else:
25                     print('用户名或密码错误')
26             elif auth_type == 'ldap':
27                 print('不知道怎么写')
28                 res = func(*args, **kwargs)
29                 return res
30             else:
31                 print('啥玩意的类型')
32                 res = func(*args, **kwargs)
33                 return res
34         return wapper
35     return auth_func
36 
37 
38 @auth(auth_type = 'filedb')  #这里执行2步(把@和auth()分开),第一步执行auth(),得到auth_func,在执行@auth_func
39 def index():
40     print('欢迎来到京东')
41 
42 @auth(auth_type = 'ldap')
43 def home(name):
44     print('%s您好,欢迎回家'%name)
45 
46 @auth(auth_type = 'sssss')
47 def shopping_car(name):
48     print('%s的购物车里有[%s,%s,%s]'%(name,'棉衣','裤子','小吃'))
49 
50 index()
51 home('苟陇辉')
52 shopping_car('苟陇辉')
53 
54 带参装饰器
带参装饰器

九 多个装饰器装饰同一个函数

 1 def wrapper1(func):  # 传入的是inner2
 2     def inner1(*args, **kwargs):
 3         print('warpper1,before')  # 2
 4         ret = func(*args, **kwargs)  # 执行inner2
 5         print('warpper1,after')  # 6
 6         return ret
 7 
 8     return inner1
 9 
10 
11 def wrapper2(func):  # 传入的是func
12     def inner2(*args, **kwargs):
13         print('warpper2,before')  # 3
14         ret = func(*args, **kwargs)  # 执行func
15         print('warpper2,after')  # 5
16         return ret
17 
18     return inner2
19 
20 def wrapper3(func):  # 传入的是inner1
21     def inner3(*args, **kwargs):
22         print('warpper3,before')  # 1
23         ret = func(*args, **kwargs)  # 执行inner1
24         print('warpper3,after')  # 7
25         return ret
26     return inner3
27 # 注意,遇到@wrapper,程序逐行加载是,把所有的@wrapper,与被装饰函数,看作同一行一起加载,
28 #        分析时从最底下的wrapper往上分析,程序内部也是从下而上执行
29 
30 
31 @wrapper3  # func = wrapper3(func)  ---> wrapper3传入的是inner1,赋值给最最新func,最最新func得到的是inner3,最下面func(),即为执行inner3()
32 @wrapper1  # func = wrapper1(func)  ---> wrapper1传入的是inner2,赋值给最新func,最新func得到的是inner1
33 @wrapper2  # func = wrapper2(func)  ---> wrapper2传入的是函数名,赋值给第一次的变量func, 第一次的变量func得到的是inner2
34 def func(*args, **kwargs):
35     print('func')  # 4
36 
37 
38 func()
三个装饰器装饰同一个函数

2种简单找出运行结果的方法:

posted @ 2018-01-21 00:52  Mr.GLH  阅读(673)  评论(0)    收藏  举报
Top↑