day13叠加多个装饰器,迭代器,生成器,三元表达式、列表生成式、字典生成式、生成器表达式

上节课复习:

闭包函数的实际应用就是装饰器,装饰器分为:
1. 无参装饰器
def outter(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
return res
return wrapper


2. 有参装饰器
def outter2(x,y,z):
def outter(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
return res
return wrapper
return outter


3. 语法糖:在被装饰对象正上方单独一行写
无参:@装饰器的名字
有参:@装饰器的名字(arg1,arg2,...)  #义括号内参数1,参数2...

@timmer # index=timmer(index)
def index():
pass

@auth2(engine='file') # @名字 # index=名字(index)
def index():
pass

今日内容:
0. 叠加多个装饰器:加载顺序与执行顺序是什么?
例如:

@装饰器1
@装饰器2 ???
@装饰器3 #f1=装饰器3(f1)
def f1():
pass

f1()


1. 迭代器(***)
2. 自定义迭代器的方式:生成器(***)

3. 三元表达式\列表生成式\生成器表达式\字典生成式(*****)

4. 函数的递归调用与二分法

5. 面向过程编程(*****)

 

补充:
1. 匿名函数(一次性的工具)+max,min,sorted,filter,reduce,map(*****)
2. 内置函数



 

 

1.加载装饰器总结:
# 加载装饰器是什么?就是将原函数名偷梁换柱成了装饰器最内层那个wrapper函数;

# 在加载完毕后,调用原函数其实就是在调用装饰器最内层wrapper函数。

2.# 当一个被装饰的对象同时叠加多个装饰器时,
# 装饰器的加载顺序是:自下而上。()己理解为:一行行代码从上而下运行阶段,装饰器语法糖的加载顺序:自下而上,所以2个阶段加载阶段先工作起来
# 装饰器内wrapper函数的执行顺序是:自上而下。()己理解为:遇到原始函数调用阶段,装饰器语法糖的执行顺序:自上而下。


# import time
#
# def timmer(func): #func=wrapper2的内存地址
# def wrapper1(*args, **kwargs):
# print('===================================>wrapper1运行了')
# start=time.time()
# res = func(*args, **kwargs) #===========================>跳到wrapper2去执行了,
# stop=time.time()
# print('run time is %s' %(stop - start))
# return res
# return wrapper1
#
# def auth(engine='file'):
# def xxx(func): # func=最原始那个index的内存地址
# def wrapper2(*args, **kwargs):
# print('===================================>wrapper2运行了')
# name=input('username>>>: ').strip()
# pwd=input('password>>>: ').strip()
# if engine == 'file':
# print('基于文件的认证')
# if name == 'egon' and pwd == '123':
# print('login successfull')
# res = func(*args, **kwargs)
# return res
# elif engine == 'mysql':
# print('基于mysql的认证')
# elif engine == 'ldap':
# print('基于ldap的认证')
# else:
# print('错误的认证源')
# return wrapper2
# return xxx
#
# @timmer # index=timmer(wrapper2的内存地址) #index=wrapper1的内存地址
# @auth(engine='file') #加载顺序:先下后上,@auth为下,@timmer为上。@xxx #index=xxx(最原始那个index的内存地址) #index=wrapper2的内存地址
# def index():
# print('welcome to index page')
# time.sleep(2)
#
# index() #wrapper1的内存地址()

一个函数上有多个装饰器运行原理总结:

程序运行时从上到下运行代码,碰到装饰器从下往上进行装饰器加载。

@装饰器1  #加载时装饰器语法糖的实质是f1=装饰器1(f1)
@装饰器2  #f1=装饰器2(f1)
@装饰器3  #f1=装饰器3(f1)
def f1():
pass

f1()调用f1函数触发装饰器执行,即加载后实质对应的函数从上往下执行。

所以装饰器执行时,实质为最上面的装饰器对下一行装饰器包了一个功能,中间的给下一行装饰器包了一个功能,最下面装饰器是给原始函数包一个功能,像包洋葱一样。通过第一句话实现给原始函数添加很多功能。



import time

def timmer(func): #func=原始函数index的内存地址。
    def wrapper1(*args, **kwargs):
        print('===================================>wrapper1运行了')
        start=time.time()
        res = func(*args, **kwargs) #===========================>跳到wrapper2去执行了,
        stop=time.time()
        print('run time is %s' %(stop - start))
        return res
    return wrapper1

def auth(engine='file'):
    def xxx(func): # func=wrapper1的内存地址。
        def wrapper2(*args, **kwargs):
            print('===================================>wrapper2运行了')
            name=input('username>>>: ').strip()
            pwd=input('password>>>: ').strip()
            if engine == 'file':
                print('基于文件的认证')
                if name == 'egon' and pwd  == '123':
                    print('login successfull')
                    res = func(*args, **kwargs)
                    return res
            elif engine == 'mysql':
                print('基于mysql的认证')
            elif engine == 'ldap':
                print('基于ldap的认证')
            else:
                print('错误的认证源')
        return wrapper2
    return xxx

@auth(engine='file')
@timmer
def index():
    print('welcome to index page')
    time.sleep(2)
index() #wrapper2的内存地址()
更换多个装饰器语法糖顺序后的分析

 



 

 

迭代器
1. 什么是迭代器?
  器》》工具。
  那么什么是迭代?

迭代指的是一个重复的过程,每一次重复的结果都是基于上一次的结果而来的。

   

li=['a','b','c','d','e']
li=('a','b','c','d','e')
li='hello'

i=0
while i < len(li):
print(li[i])
i+=1
迭代器指的是迭代取值的工具,该工具的特点是可以不依赖于索引取值。
2. 为何要用迭代器?
   对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。
   但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器。

为了找出一种通用的并且可以不依赖于索引的迭代取值方式。

3. 如何用迭代器?
可迭代的对象:但凡内置有.__iter__方法的对象都称之为可迭代的对象。
迭代器对象:既内置有__iter__方法,又内置有__next__方法的对象。
   总结:迭代器对象一定是可迭代对象,但可迭代对象不一定是迭代器对象。

内置__iter__方法是为了用,怎么用? 关于__iter__方法:
调用可迭代对象的__iter__会得到一个迭代器对象。
调用迭代器对象的__iter__会得到迭代器本身。

4. 总结迭代器的优缺点:
优点:
1. 提供了一种通用的并且可以不依赖于索引的迭代取值方式。
2. 同一时刻在内存中只有一个值,更加节省内存。
eg:定义一个列表,列表会申请内存空间存列表内所有的值,当值比较多时会很占内存。
而创造一个迭代器对象时,不会把值放到内存,只是在取值时同一时刻内存中只有一个值。


缺点:
1. 不能取指定值不如索引灵活,并且迭代器是一次性的。
2. 无法预知迭代器数据的个数。

'''
# 可迭代的对象: str,list,tuple,dict,set,文件对象。
# 迭代器对象: 文件对象。

# 可迭代的对象=====》迭代器对象:调用可迭代对象内置的__iter__方法会有一个返回值,该返回值就是对应的迭代器对象。
dic={'x':1,'y':2,'z':3}

针对一个迭代器,用多个next方法取值:会迭代取到值。
# iter_dic=dic.__iter__()
# # print(iter_dic)
# res1=iter_dic.__next__()
# print(res1)
#
# res2=iter_dic.__next__()
# print(res2)
#
# res3=iter_dic.__next__()
# print(res3)
#
# res4=iter_dic.__next__()
# print(res4) 》》》报错stopitnation!!


针对多个迭代器用next方法取值:都是取到同一个值。
iter_dic=dic.__iter__()
iter_dic=dic.__iter__()
iter_dic=dic.__iter__()#得到3个迭代器。
# print(iter_dic.__next__())
# print(iter_dic.__next__())
# print(iter_dic.__next__())
或者这样写:与上面意思一样。
# print(dic.__iter__().__next__())
# print(dic.__iter__().__next__())
# print(dic.__iter__().__next__())


# dic={'x':1,'y':2,'z':3}
# # dic=['a','b','c']
# iter_dic=dic.__iter__()
#
# # iter_dic=open(r'D:\上海python全栈4期\day13\今日内容',mode='rt',encoding='utf-8')
#
# while True:
# try:
# print(iter_dic.__next__())
# except StopIteration:
# break

# for准确地说应该是迭代器循环,for循环的原理如下:
#1. 先调用in后面那个值的__iter__方法,得到迭代器对象;
#2. 执行迭代器.__next__()方法得到一个返回值,然后赋值给一个变量k,运行循环体代码;’
#3, 循环往复,直到迭代器取值完毕抛出异常然后,自动捕捉异常结束循环。

dic={'x':1,'y':2,'z':3}
iter_dic=dic.__iter__()
print(iter_dic)
print(iter_dic.__iter__())

# for k in dic: #iter_dic=dic.__iter__()
# print(k)



# with open(r'D:\上海python全栈4期\day13\今日内容',mode='rt',encoding='utf-8') as f:
# for line in f: #iter_f=f.__iter__()
# print(line)



#yield关键字:只能用在函数内!
# 在函数内但凡包含有yield关键字,再去执行函数,就不会立刻运行函数体代码了。
# 生成器函数会得到一个返回值,该返回值成之为生成器对象,生成器本质就是迭代器。

# 总结yield:
# 1. 提供一种自定义迭代器的解决方案!

# 2. yield可用于返回值。
# yield VS return
# 相同点:都可以用于返回值不限制出现的个数,不限制值的类型和几个。
# 不同点:yield可以暂停函数,yield可以返回多次值,而return只能返回值一次值函数就立刻终止

# def func():
# print('=====>第一次')
# yield 1
# print('=====>第二次')
# yield 2
# print('=====>第三次')
# yield 3
# print('=====>第四次')
#
# # print(func)
#
# g=func()
# # print(g.__iter__().__iter__().__iter__() is g)
# # iter(g) #g.__iter__()
# # next(g) #g.__next__()
#
# res1=next(g)
# print(res1)
#
# res2=next(g)
# print(res2)
#
# res3=next(g)
# print(res3)
#
# res4=next(g)
# print(res4)



def my_range(start,stop,step=1):
while start < stop:
yield start
start+=step

res=my_range(1,5,2) # 1 3

next(res)
next(res)
# print(next(res))
# for item in res:
# print(item)



for item in my_range(1,5,2):
print(item)

 



 

# 三元表达式
三元表达式基本形式:
res=条件成立的值(可以是一个或多个值逗号隔开) if条件 条件不成立的值(同前)

# def max2(x,y):
# if x > y:
# return x
# else:
# return y
#
# x=10
# y=20
# res='条件成立的值' if x > y else '条件不成立的值'
# print(res)

# 列表生成式
# l=[]
# for i in range(1,11):
# if i > 4:
# res='egg%s' %i
# l.append(res)
# print(l)
#
# l=['egg%s' %i for i in range(1,11) if i > 4]
# print(l)
上面意思:for循环一次取到一个值给i,判断一次,符合条件就加入列表,不符合不加入,这样的操作执行多次。

# names=['egon','lxx','yyx','cw','alex','wxx']
# l=[]
# for name in names:
# if name != 'egon':
# res='%s_DSB' %name
# l.append(res)
# print(l)
#
# l=['%s_DSB' %name for name in names if name != 'egon']
# print(l)

# 生成器表达式
# res=(i**2 for i in range(3))
# print(res)
# print(next(res))
# print(next(res))
# print(next(res))
# print(next(res))


with open(r'D:\上海python全栈4期\day13\今日内容',mode='rt',encoding='utf-8') as f:
# data=f.read()
# print(len(data)) #1025

# res=0
# for line in f:
# res+=len(line)
# print(res)

# res=sum((len(line) for line in f))
# res=sum(len(line) for line in f)
# print(res)

# res=max([len(line) for line in f])
# res=max((len(line) for line in f))
res=max(len(line) for line in f)
print(res)

# 字典生成式
# items=[('name','egon'),('age',18),('sex','male')]

# dic={}
# for k,v in items:
# dic[k]=v
# print(dic)

# res={k:v for k,v in items if k != 'sex'}
# print(res)


# res={i for i in 'hello'}
# print(res)
posted @ 2018-09-28 21:34  timm_book  阅读(53)  评论(0)    收藏  举报