import time def timer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper @timer #把@timer放到foo()函數的定義處,至關於執行了foo=timer(foo) def foo(): time.sleep(3) print('from foo') foo() """執行結果 from foo run time is 3.000171661376953 """
def timer2(ms = 'file'): def timer(func): def wrapper(*args, **kwargs): if ms == 'file': name = 'file_name' res = func(*args, **kwargs) print('%s login successful'%name) return res elif ms == 'mysql': name = 'mysql_name' res = func(*args, **kwargs) print('%s login successful'%name) return res else: name = 'other_name' res = func(*args, **kwargs) print('%s login successful'%name) return res return wrapper return timer @timer2(ms = 'file') #timer2(ms = 'file')返回timer函數引用 就和無參的同樣了 def foo(name): print('from foo %s'%name) foo('rose') """ from foo rose file_name login successful """
# 疊加多個裝飾器 # 1. 加載順序(outter函數的調用順序):自下而上 # 2. 執行順序(wrapper函數的執行順序):自上而下 def outter1(func1): # func1=wrapper2的內存地址 print('加載了outter1') def wrapper1(*args, **kwargs): print('執行了wrapper1') res1 = func1(*args, **kwargs) return res1 return wrapper1 def outter2(func2): # func2=wrapper3的內存地址 print('加載了outter2') def wrapper2(*args, **kwargs): print('執行了wrapper2') res2 = func2(*args, **kwargs) return res2 return wrapper2 def outter3(func3): # func3=最原始的那個index的內存地址 print('加載了outter3') def wrapper3(*args, **kwargs): print('執行了wrapper3') res3 = func3(*args, **kwargs) return res3 return wrapper3 # 被裝飾函數的正上方,單獨一行 @outter1 # outter1(wrapper2的內存地址)======>index=wrapper1的內存地址 @outter2 # outter2(wrapper3的內存地址)======>wrapper2的內存地址 @outter3 # outter3(最原始的那個index的內存地址)===>wrapper3的內存地址 def index(): # index=outter1(outter2(outter3(index))) print('from index') print('==========================') index() """ 加載了outter3 加載了outter2 加載了outter1 ========================== 執行了wrapper1 執行了wrapper2 執行了wrapper3 from index """
對於序列類型:字符串、列表、元組,咱們可使用索引的方式迭代取出其包含的元素。但對於字典、集合、文件等類型是沒有索引的,若還想取出其內部包含的元素,則必須找出一種不依賴於索引的迭代方式,這就是迭代器,迭代器有節省內存的好處。mysql
可迭代對象指的是內置有__iter__方法的對象,即obj.__iter__,以下sql
""" #優勢: - 提供一種統一的、不依賴於索引的迭代方式 - 惰性計算,節省內存 #缺點: - 沒法獲取長度(只有在next完畢才知道到底有幾個值) - 一次性的,只能日後走,不能往前退,迭代完,就不能再次迭代 """ dic={'a':1,'b':2,'c':3} iter_dic=dic.__iter__() #獲得迭代器對象,迭代器對象即有__iter__又有__next__ 迭代器對象.__iter__()後仍然是迭代器對象自己 print(iter_dic) #<dict_keyiterator object at 0x0000000000BA99F8> print(iter_dic.__iter__()) #<dict_keyiterator object at 0x0000000000BD99F8> print(iter_dic.__iter__() is iter_dic) #True 迭代器對象.__iter__()後仍然是迭代器對象自己 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(k,dic[k]) except StopIteration: # 須要咱們本身捕捉異常 break #基於for循環,咱們能夠徹底再也不依賴索引去取值了 dic={'a':1,'b':2,'c':3} for k in dic: print(k, dic[k]) print('123123213') for k in dic: print(k, dic[k]) #for循環的工做原理 #1:執行in後對象的dic.__iter__()方法,獲得一個迭代器對象iter_dic #2: 執行next(iter_dic),將獲得的值賦值給k,而後執行循環體代碼 #3: 重複過程2,直到捕捉到異常StopIteration,結束循環
dir([1,2].__iter__())#是列表迭代器中實現的全部方法, dir([1,2]) #是列表中實現的全部方法,都是以列表的形式返回,爲了看的更清楚,分別把他們轉換成集合,而後取差集。 # print(dir([1,2].__iter__())) # 返回一個列表 # print(dir([1,2])) print(set(dir([1,2].__iter__()))-set(dir([1,2]))) #{'__length_hint__', '__next__', '__setstate__'} #列表迭代器中多了三個方法 iter_l = [1,2,3,4,5,6].__iter__() #獲取迭代器中元素的長度 print(iter_l.__length_hint__()) #6 #根據索引值指定從哪裏開始迭代 print('*',iter_l.__setstate__(4)) #* None #一個一個的取值 print('**',iter_l.__next__()) #** 5 print('***',iter_l.__next__()) #*** 6 print('__next__' in dir(range(12))) #False print('__iter__' in dir(range(12))) #True from collections import Iterator print(isinstance(range(100000000),Iterator)) # False 驗證range執行以後獲得的結果不是一個迭代器
from collections import Iterable,Iterator class Foo: def __init__(self,start): self.start=start def __iter__(self): return self def __next__(self): return 'aSB' f=Foo(0) print(isinstance(f,Iterable)) #True 可迭代 print(isinstance(f,Iterator)) #True 迭代器
""" 生成器表達式: 優勢:省內存,一次只產生一個值在內存中 把列表推導式的[]換成()就是生成器表達式 """ gen_exp = (i for i in range(10)) #生成器表達式 print(gen_exp) #<generator object <genexpr> at 0x0000000000A1DEB8> # for i in gen_exp: #取出生成器表達式的值,for循環 # print(i) print(gen_exp.__next__()) #next方法 print(gen_exp.__next__()) print(gen_exp.__next__())
egg_list=['雞蛋%s' %i for i in range(10)] #列表解析 print(egg_list) #['雞蛋0', '雞蛋1', '雞蛋2', '雞蛋3', '雞蛋4', '雞蛋5', '雞蛋6', '雞蛋7', '雞蛋8', '雞蛋9'] laomuji=('雞蛋%s' %i for i in range(10))#生成器表達式 print(laomuji) #<generator object <genexpr> at 0x0000000000BA3938> print(next(laomuji)) #雞蛋0 next本質就是調用__next__ print(laomuji.__next__()) #雞蛋1 print(next(laomuji)) #雞蛋2 #sum函數是Python的內置函數,該函數使用迭代器協議訪問對象,而生成器實現了迭代器協議,因此,能夠直接這樣計算一系列值的和: print(sum([x ** 2 for x in range(4)])) #14 #而不用畫蛇添足的先構造一個列表: print(sum(x ** 2 for x in range(4))) #14 ################################### def demo(): for i in range(4): yield i g=demo() g1=(i for i in g) g2=(i for i in g1) print(list(g1),type(g1)) #[0, 1, 2, 3] <class 'generator'> print(list(g2)) #[] ################################### def demo(): for i in range(4): yield i g=demo() g1=[i for i in g] g2=(i for i in g1) print(list(g1),type(g1)) #[0, 1, 2, 3] <class 'list'> print(list(g2)) #[0, 1, 2, 3] print(list(g2)) #[]
""" 生成器函數: 只要函數內部包含有yield關鍵字,那麼函數名()的到的結果就是生成器,而且不會執行函數內部代碼 生成器就是迭代器(執行函數獲得生成器) """ def product(): for i in range(1, 3): print("開始生產包子") yield "第 %d 屜包子" % (i) print("賣包子,買完再生產") pro = product() # 生成一個作包子的生成器,至關於作包子的 print(pro) p = print(pro.__next__()) # 賣包子的 print('===') print(pro.__next__()) print('============') for i in pro: print(i) """ <generator object product at 0x00000000006DDEB8> 開始生產包子 第 1 屜包子 === 賣包子,買完再生產 開始生產包子 第 2 屜包子 ============ 賣包子,買完再生產 """ def product(): for i in range(1,3): print("開始生產包子") yield "第 %d 屜包子" %(i) print("賣包子,買完再生產") pro = product() #生成一個作包子的生成器,至關於作包子的 while 1: try: k=next(pro) print(k) except StopIteration: # 須要咱們本身捕捉異常 break
#生成器函數 def my_range(): print('我是一個生成器函數') n = 0 while 1: yield n n += 1 #實現開始和結束 def my_range2(start, stop): n = start while n < stop: yield n n += 1 #再進一步,實現步長: def my_range3(start, stop, step): n = start while n < stop: yield n n += step #生成器本質上就是個迭代器,咱們根據本身的想法創造的迭代器,它固然也支持for循環: for i in my_range3(1, 10, 2): print(i)
import time def tail(filename): f = open(filename) f.seek(0, 2) #從文件末尾算起 while True: line = f.readline() # 讀取文件中新的文本行 if not line: time.sleep(0.1) continue yield line tail_g = tail('tmp') for line in tail_g: print(line)
def gen1(): for c in 'AB': yield c for i in range(3): yield i print(gen1()) #['A', 'B', 0, 1, 2] def gen2(): yield from 'AB' yield from range(3) print(list(gen2())) #['A', 'B', 0, 1, 2]
import pickle class Course: def __init__(self,name,price,period,teacher): self.name = name self.price = price self.period = period self.teacher = teacher def get_course(): with open('course_info', 'rb') as f: while True: try: course_obj = pickle.load(f) yield course_obj except EOFError: break cour=get_course() print(cour) print(cour.__iter__()) print(cour.__next__()) print(cour.__next__()) for obj in cour: print(obj.name) ############################ def get_line(): with open('a.txt', encoding='utf-8', mode='r') as f: while True: try: line = f.readline() yield line except StopIteration: break g=get_line() print(g) print(g.__next__()) print(g.__next__()) print(g.__next__())
""" 協程函數: yield關鍵字的另一種使用形式:表達式形式的yield 對於表達式形式的yield,在使用時,第一次必須傳None,g.send(None)等同於next(g) yield總結 一、把函數作成迭代器 二、對比return,能夠返回屢次值,能夠掛起/保存函數的運行狀態 """ def eater(name): print('%s 準備開始吃飯啦' % name) food_list = [] for i in range(4): food = yield food_list print('%s 吃了 %s' % (name, food)) food_list.append(food) print('while', food_list) # print('eater',food_list) ####這的代碼不會執行,尚未走到這程序就退出了 g = eater('tom') print(g) g.send(None) # 對於表達式形式的yield,在使用時,第一次必須傳None,g.send(None)等同於next(g) print('====') g.send('包子') g.send('米飯') g.send('麪條') try: g.send('稀飯') except StopIteration: g.close() #依舊執行後面的print(g) # quit() #後面的print(g)就不執行了 try: g.send('肉夾饃') except StopIteration: g.close() print(g) """ <generator object eater at 0x0000000000BA1BF8> tom 準備開始吃飯啦 ==== tom 吃了 包子 while ['包子'] tom 吃了 米飯 while ['包子', '米飯'] tom 吃了 麪條 while ['包子', '米飯', '麪條'] tom 吃了 稀飯 while ['包子', '米飯', '麪條', '稀飯'] <generator object eater at 0x0000000000BA1BF8> """ # 單線程一邊發送,一邊執行 import time def consumer(name): print("%s 準備吃包子啦!" % name) while True: food = yield print("包子[%s]來了,被[%s]吃了!" % (food, name)) def producer(name): c = consumer('顧客A') c2 = consumer('顧客B') c.__next__() c2.__next__() print("老闆%s==開始準備作包子啦!" % name) for i in range(3): time.sleep(1) print("作了2個包子!") c.send(i) # 發送的值,就是yield的返回值 c2.send(i) producer("tom") print('===========') producer("jack") """ 顧客A 準備吃包子啦! 顧客B 準備吃包子啦! 老闆tom==開始準備作包子啦! 作了2個包子! 包子[0]來了,被[顧客A]吃了! 包子[0]來了,被[顧客B]吃了! 作了2個包子! 包子[1]來了,被[顧客A]吃了! 包子[1]來了,被[顧客B]吃了! 作了2個包子! 包子[2]來了,被[顧客A]吃了! 包子[2]來了,被[顧客B]吃了! =========== 顧客A 準備吃包子啦! 顧客B 準備吃包子啦! 老闆jack==開始準備作包子啦! 作了2個包子! 包子[0]來了,被[顧客A]吃了! 包子[0]來了,被[顧客B]吃了! 作了2個包子! 包子[1]來了,被[顧客A]吃了! 包子[1]來了,被[顧客B]吃了! 作了2個包子! 包子[2]來了,被[顧客A]吃了! 包子[2]來了,被[顧客B]吃了! """
# def eat(name): # print('%s要開始吃了!' % name) # while 1: # food = yield # print('{}在吃{}'.format(name, food)) # # # a = eat('alex') # a.__next__() # 初始化,讓函數暫停在yield處 # a.send('包子') # send兩個做用:1.給yield傳值 2.繼續執行函數 # a.send('餃子') def init(func): #在調用被裝飾生成器函數的時候首先用next激活生成器 def inner(*args,**kwargs): g = func(*args,**kwargs) next(g) return g return inner @init def averager(): total = 0.0 count = 0 average = None while True: term = yield average total += term count += 1 average = total/count g_avg = averager() # next(g_avg) 在裝飾器中執行了next方法 print(g_avg.send(10)) #10.0 print(g_avg.send(30)) #20.0 print(g_avg.send(5)) #15.0