python(六)——装饰器,迭代器,生成器

装饰器

def function(f):
    def inner(*args,**kwagrs):
        start = time.time()
        ret = f(*args,**kwagrs)
        end =time.time() - start
        print('程序运行时间为%.4f'% end)
        return ret
    return inner
@function
def code(n):
    for i in range(n):
        print(i)
    
code(10000)
print(code.__name__)#inner
'''
变量名.__name__ 查看实际调用函数名
实际是调用inner,被装饰方法名无法获取
解决:添加一个内置的装饰器@wraps()
from functools import wraps

def function(f):
    @wraps(f)
    def inner(*args,**kwagrs):
      
        ret = f(*args,**kwagrs)
     
        return ret
    return inner
@function
def code(n):
    for i in range(n):
        print(i)
    
code(10000)
print(code.__name__)
'''

带参数的装饰器

根据标记值的不同来决定是否增强代码
f = True
d = False
def function(flag):
    def timmer(f):
        def inner(*args,**kwagrs):
            ret = f(*args,**kwagrs)
            if flag:
                print(f.__name__ + '代码已经增强')
                return ret
            return ret
        return inner
    return timmer

@function(f)
def test1():
    print('test1函数')
    
@function(d)
def test2():
    print('test2函数')
test1()   
test2() 

多个装饰器装饰一个函数

def function(f):
    def inner(*args,**kwagrs):
        print('装饰器---1----before')
        ret = f(*args,**kwagrs)
        print('装饰器---1----after')
        return ret
    return inner

def function2(f):
    def inner2(*args,**kwagrs):
        print('装饰器---2----before')
        ret = f(*args,**kwagrs)
        print('装饰器---2----after')
        return ret
    return inner2
   
@function2
@function
def test1():
    print('test1函数')

test1()
'''
装饰器---2----before
装饰器---1----before
test1函数
装饰器---1----after
装饰器---2----after

执行流程
@function2等价于test1 = function2(test1)等价于function2(function(test1))即function2(inner)
@function等价于test1 = function(test1)返回inner
test1() 调用 function2(inner)()等于inner2(),inner2()中f=inner,f()就是inner()
'''

迭代器

可迭代协议:

只要含有__iter__方法的都是可迭代的
list,dict,set,tuple,enumerate都是可迭代的 

dir(class)  获取class类中所有的方法

迭代器协议:

	只要含有__iter__方法和__next__方法的都是迭代器
	迭代器是一个可以记住遍历的位置的对象
	迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
	同一个迭代器对象中的值只能取一次
print(dir([]))#获取列表所有方法名 ,其中有_iter_

#通过可迭代对象得到一个对应的迭代器
re= [].__iter__()  
print(re)
'''
迭代器常用的3个方法:
__length_hint__ ()返回迭代器中元素个数
__setstate__()从指定位置处开始迭代
__next__()取出迭代器中下一个值,没有值,会抛出StopIteration异常,以终止迭代 
'''
l=[3,5,6,8,9,8]
re= l.__iter__()#获取一个迭代器
print(re)#<list_iterator object at 0x00000000006CD3C8>
for i in re:#同一个迭代器
    print(i)#3 5 6 8 9 8
    
for i in re:#同一个迭代器
    print(i)#无输出,同一个迭代器对象只能取一次值

l=[3,5,6,8,9,8]
for i in l:#同一个对象
    print(i)#3 5 6 8 9 8
    
for i in l:#同一个对象
    print(i)#3 5 6 8 9 8
'''
for循环的本质:基于迭代器协议提供了一个统一的可以遍历所有对象的方法,
即在遍历之前,先调用对象的__iter__方法将其转换成一个对应的迭代器,
然后使用迭代器的__next__方法依次循环元素,当元素循环完时,
会触发StopIteration异常,for循环会捕捉到这种异常,终止迭代;
''' 

如何确定一个对象是可迭代的还是迭代器

from collections.abc import Iterable,Iterator
l=[]
print(isinstance(l, Iterable))#True	判定l对象是否可迭代
print(isinstance(l, Iterator))#False	判定l对象是否是迭代器

生成器

	生成器本质是迭代器
	生成器一次只能产生一个值,在需要时再去生成值,节省内存
	生成器的应用方式
			1.生成器函数
			2.生成器表达式		

生成器函数

def generator():
    for i in range(15):
        yield '生成器%d' % i
        
        
g = generator()
print(g)#<generator object generator at 0x0000000000572F48>
print(g.__next__())
'''
含有yield关键字的函数都是生成器函数
yield关键字只能在函数内部
有yield就不能有return
yield可以将后面的值返回,和return类似
yield执行后代码未结束。等待下一次取值,从此次断点继续执行
生成器函数执行后会得到一个生成器,此时函数内代码不会执行
真正获取值的时候,内部代码才会执行

生成器函数取值的方法
1.__next__() 一次取一个值,需要处理最后一个值输出后的StopIteration异常
2.for循环	如果没有break,会一次读取完所有的值
3.强制类型转换
	list(g) 会将所有数据一次性加载到内存中
4.send() 不能用来取第一个yield值,既能取值,也能传值

'''

生成器表达式

e=(i for i in range(10))#得到一个生成器
print(e)#<generator object <genexpr> at 0x0000000000472EC8>
st = (y + x for x in '345' for y in '♠♥♣♦')
for i in st:
    print(i,end = ' ')#♠3 ♥3 ♣3 ♦3 ♠4 ♥4 ♣4 ♦4 ♠5 ♥5 ♣5 ♦5 

生成器进阶

send() :生成器方法,获取生成器的下一个值,和next类型,同时传一个值给当前的yield表达式
#获取移动平均值
def generator():
    su = 1
    count = 1
    while 1:
        nu = yield su / count
        su += nu
        count += 1
        
g = generator()
print(g.__next__())#1.0
print(g.send(5))#3.0
print(g.send(6))#4.0

对于生成器的send(),第一次必须用__next__()后才能使用或者send(None)。可以与装饰器配合

def adornment(f):
    def inner(*args,**kwargs):
        g = f(*args,**kwargs)
        g.__next__()#或者	next(g) 本质是调用了g.__next__()
        return g
    return inner



@adornment
def generator():
    su = 1
    count = 1
    while 1:
        nu = yield su / count
        su += nu
        count += 1
        
g = generator()#装饰器执行
print(g.send(5))#3.0
print(g.send(6))#4.0

yield from 应用

def generator1(l1):
    yield from l1

l = '345'
g = generator1(l)

for i in g :
    print( i ,end = ' ')#3 4 5 

查询文件中指定内容,并返回当前行内容

def check_Content(fileName,keyword):
    with open(fileName, encoding = 'utf-8' ) as f:
        for i in f :
            if keyword in i :
                yield i 


g = check_Content('filedown','天使')
for i in g:
    print(i,end = ' ')

yield 转载https://blog.csdn.net/jason_cuijiahui/article/details/84947310

def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

c = consumer()
produce(c)

文件夹中查找指定文件内容返回文件名 转载:https://www.cnblogs.com/Eva-J/articles/7213953.html

import os

from functools import wraps
#第一步
def init(func):
	#第三步——list_files 
	#第五步——opener
	#第七步——cat
	#第九步——grep
	#第十一步——printer
    @wraps(func)
    def wrapper(*args,**kwargs):
   		 #第十三步——printer
   		 #第十六步——grep
   		  #第十九步——cat
   		  #第二十二步——opener
   		  #第二十五步——list_files 
        print(func.__name__)#查看被装饰的方法名	printer grep cat opener list_files 
        g=func(*args,**kwargs)
        next(g)
        #第十五步——printer
        #第十八步——grep
        #第二十一步——cat
        #第二十四步——opener
        #第二十七步——list_files
        return g
    return wrapper
#第二步
@init
def list_files(target):
    while 1:
    	#第二十六步——list_files
        dir_to_search=yield	#传入一个目录路径
        #第二十九步
        for top_dir,dir,files in os.walk(dir_to_search):#遍历一个目录内各个子目录和子文件
        	#top_dir 是dir_to_search代表目录的路径
        	#dir 是dir_to_search下所有子目录的名字组成的列表
        	#top_dir 是dir_to_search下非目录文件的名字组成的列表。
            for file in files:		#遍历列表 获取文件名
            #第三十步
            #第四十步
            
                target.send(os.path.join(top_dir,file))	#给opener(target)的yield表达式传入一个文件的绝对地址
#第四步
@init
def opener(target):
    while 1:
    	#第三十九步
    	#第二十三步——opener
        file=yield
        #第三十一步
        #第四十一步
        fn=open(file)	#根据传入的文件地址打开这个文件
        target.send((file,fn))	#给cat(target)的yield表达式传入文件地址和文件操作对象
#第六步
@init
def cat(target):
    while 1:
    	#第三十八步
    	#第二十步
        file,fn=yield
        #第三十二步
        #第四十二步
        for line in fn:	#通过文件操作对象获取文件内容
            target.send((file,line))	#给grep(pattern,target)的yield表达式传入文件地址和一行文件内容

#第八步
@init
def grep(pattern,target):
    while 1:
    	 #False #第三十五步
        #False #第三十六步
        #False #第三十七步
        #。。。。。
     	#第十七步
        file,line=yield
        #第三十三步
        #第四十三步
        if pattern in line:	#判断这一行文件内容中是否有关键字pattern
        	#True 第四十四步
            target.send(file)	#如果有关键字就给printer()的yield表达式传入文件地址
        #False #第三十四步
       
#第十步
@init
def printer():
    while 1:
    	#第四十七步
	    #第十四步
        file=yield
        #第四十五步
        if file:
       		 #第四十六步
            print(file)	#输出含有关键字的文件的地址
#第十二步
g=list_files(opener(cat(grep('python',printer()))))	#得到生成器
#第二十八步
g.send(r'E:\test')

yield函数面试题

def dome():
    for i in range(5):
        yield i
        
g = dome()
g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g1))	#[0, 1, 2, 3, 4]
print(list(g2))	#[]
#生成器只能取一次值
def add(n,i):
    return n+i

def test():
    for i in range(4):
        yield i

g=test()
for n in [3,6,9]:
    g=(add(n,i) for i in g)

print(list(g))#[27, 28, 29, 30]
'''
for n in [3,6,9]:
    g=(add(n,i) for i in g)
解析
n = 3
g=(add(n,i) for i in g)
n = 6
g=(add(n,i) for i in g)
n = 9
g=(add(n,i) for i in g)
所以只需要看n=9时g的值即可
n = 9
g=(add(n,i) for i in g) 
=(add(n,i) for i in ((add(n,i) for i in g))) 
=(add(n,i) for i in ((add(n,i) for i in (add(n,i) for i in g)))) 
=(add(9,i) for i in ((add(9,i) for i in (add(9,i) for i in range(4))))) 
=(add(9,i) for i in ((add(9,i) for i in (9,10,11,12))))
=(add(9,i) for i in ((18,19,20,21)))
=(27,28,29,30)


'''
发布了16 篇原创文章 · 获赞 0 · 访问量 77

猜你喜欢

转载自blog.csdn.net/qq_31241107/article/details/103786547