python的装饰器、迭代器、yield_python装饰器,迭代器,生成器,协程
python裝飾器[1]
首先先明白以下兩點
#嵌套函數
defout1():definner1():print(1234)
inner1()#當沒有加入inner時out()不會打印輸出1234,當前層級也就是作用域下必須調用函數才能引用
out1()
#函數作用域
defout2():
a= 'aaa'
definner2():
a= 'bbb'
print(a)
inner2()print(a)
out2()#當相同變量處于不同嵌套函數中,會根據作用函數由內而外查找
裝飾器:本質還是一個函數, 在不改變函數調用方式的情況下 對函數進行額外功能的封裝,裝飾一個函數 轉給他一個其他的功能
裝飾器的目的:裝飾器的原本是用來在項目上線之后,因為已經上線了,大批量改代碼的話很麻煩,由此產生了裝飾器
不能修改被裝飾的函數的源代碼
不能修改被裝飾的函數的調用方式
importtimedefdemo():print("wo shi rainbol")deftime1():
start=time.time()
demo()#給time1函數增加了一個demo的功能
end =time.time()print(end-start)
time1()#這樣方式很low,如果有一個添加n個函數添加此功能會很麻煩
importtimedefdemo():print("wo shi rainbol")defdemo2():print("wo yeshi rainbol")deftime1(fuc):
start=time.time()
fuc()#把之前的demo改成公用的fuc,函數即變量
end =time.time()print(end-start)
time1(demo)#通過調用time1方法,fuc賦值成了demo,再調用demo的方法
time1(demo2)#time1(demo。。)
以上完成了對任意函數改變調用方式進行了功能的封裝,那如何用不改變調用方式的情況下對其進行功能的封裝呢?
importtimedefdemo():print("wo shi rainbol")deftime1(fuc):def inner():#根據之前學過的嵌套函數,增加一層inner方法,把值放入其中
start =time.time()
fuc()
end=time.time()print(end-start)return inner#返回inner方法,但是沒有運行
demo = time1(demo)#time1包含了inner的功能/拿到inner的返回值并且賦值給res,裝飾器的目的是不改變變量名所以這邊仍然用demo變量賦值
demo()#demo通過括號運行inner方法
#下面通過真正的裝飾器可以省去上面的步驟
importtimedeftime1(fuc):#2.time1(demo),這里的fuc相當于形參,其實就是demo
definner():
start=time.time()
fuc()
end=time.time()print(end-start)returninner#3.返回inner函數,但沒有執行哦
@time1#1.python先會整體瀏覽一遍代碼關鍵字的代碼,找到了demo方法上頭有裝飾
# 先調用裝飾器,time1也就是demo = time1(demo),括號中的demo相當于實參
defdemo():print("wo shi rainbol")
# demo = time1(demo) <=====> @time1 去掉@time1在這家這段也是一樣的
demo()#4.現在才執行()執行函數
#簡單裝飾器
importtimedefsimper(fuc):def inner(*args,**kwargs):
start=time.time()
fuc(*args,**kwargs)#增加的方法
end =time.time()print(end -start)returninner
@simper#demo = simper(demo)
def demo(name):#定義一個方法
print(name)#增加一個公用的功能點
demo(1)
#高級裝飾器 當我們再原來裝飾器的業務上再增加一個形參,來判斷我們的業務是否符合指定的狀態,這需要外面再套一層函數
importtimedefharder(type):if type == 1:defout(fuc):def inner(*args,**kwargs):
start=time.time()
fuc(*args,**kwargs)
end=time.time()print(end -start)returninnerreturnoutelif type == 2:pass@harder(1)#返回out函數
defdemo(name):print(name)
demo(1)
python裝飾器[2]
裝飾器與之間的迭代
下面是產品四次提出需求后再不修改調用參數使用裝飾器在修改lose函數來完成我們業務上的需求,原因是上線項目許多接口都調用我們這個類下的參數,再不破壞接口本身情況下使用裝飾器迭代是最佳選擇
importtime#現在有一個需求1.0:在整個功能的基礎上再添加一個減去4.5的操作使得最后結果為0,前提條件是不修改調用參數
defouter(fuc):def inner(*args, **kwargs):
a= fuc(*args, **kwargs) - 4.5
returnareturninner#迭代需求1.1:在整個功能的基礎上再添加一個增加10的操作使得最后結果為10,提前條件是不修改調用參數
defouter2(fuc2):def inner2(*args, **kwargs):
b= fuc2(*args, **kwargs) + 10
returnint(b)returninner2#迭代需求1.2:在整個功能的基礎上再添加一個時間參數判斷lose函數的時間,目前為了模擬添加2秒延遲時間,提前條件是不修改調用參數
defshowtime(fuc):def inner3(*args, **kwargs):
starttime=time.time()
a= fuc(*args, **kwargs)
time.sleep(2)
endtime=time.time()
b= endtime -starttimereturna, breturninner3#迭代需求2.0:目前項目的lose的方法在業務繁忙時會異常中斷,為此接口添加異常處理,提前條件是不修改調用參數
deftryexception(fuc):def tryer(self, *args, **kwargs):try:
res= fuc(self, *args, **kwargs)exceptException as e:
self.lose()return 'ERROR'
returnresreturntryer
'''主程序'''classMyDecorato(object):def __init__(self):pass
defchengxu(self, a, b):
c= a +breturnc
@tryexception#4.最后調用tryexception裝飾器,裝飾器之間調用是從下到上來依次調用
@showtime #3.調用showtime裝飾器
@outer2 #2.調用outer2裝飾器
@outer #1.先調用outer裝飾器
deflose(self, c):#頻繁調用的函數lose
pingjun= c / 2
returnpingjun
d=MyDecorato()
res1= d.chengxu(6, 3)
res2, time=d.lose(res1)print('最后的值:', res2, '時間:', time)
python裝飾器[3]
#wrap函數為functools標準庫中模塊
deftest():'''i am test'''
print('一個簡單的實驗')
test()print(test.__doc__)print(test.__name__)#
#>> 一個簡單的實驗#>> i am test#>> test
print('--------------------------------')defouter(fuc):'''outer is me'''
print('this is outer')def inner(*args,**kwargs):'''inner is me'''
print('this is inner1')
fuc(*args,**kwargs)print('this is inner2')returninner
@outerdeftest():'''i am test'''
print('一個簡單的實驗')
test()print(test.__doc__)print(test.__name__)#>> this is outer#>> this is inner1#>> 一個簡單的實驗#>> this is inner2#>> inner is me#>> inner
print('-----------------------')#如果我們想要得到test里面的數據就要調用一個特定裝飾器來幫我們實現
importfunctoolsdefouter(fuc):'''outer is me'''
print('this is outer')#@functools.wraps(fuc)
def inner(*args,**kwargs):'''inner is me'''
print('this is inner1')
fuc(*args,**kwargs)print('this is inner2')#return inner
return functools.update_wrapper(inner,fuc)#@functools.wraps(fuc)也可以,update_wrapper是調用其內部wrapper
@outerdeftest():'''i am test'''
print('一個簡單的實驗')
test()print(test.__doc__)print(test.__name__)#>> this is outer#>> this is inner1#>> 一個簡單的實驗#>> this is inner2#>>> i am test#>> test
print('------------------')#保持wrapper和test的屬性值一樣,這樣也可以實現同樣的效果
importfunctoolsdefouter(fuc):'''outer is me'''
print('this is outer')def inner(*args,**kwargs):'''inner is me'''
print('this is inner1')
fuc(*args,**kwargs)print('this is inner2')
inner.__doc__ = fuc.__doc__inner.__name__ = fuc.__name__
returninner
@outerdeftest():'''i am test'''
print('一個簡單的實驗')
test()print(test.__doc__)print(test.__name__)
python裝飾器[4]
#通過類中的裝飾器實現,普通方式
classFoo(object):def __init__(self):pass
defdecorator(foo):definner(self):print('before')
foo(self)print('after')returninner
@decoratordeftest(self):print('testing')
foo=Foo()
foo.test()
#通過類中的裝飾器實現,繼承方式
classFoo(object):def __init__(self):pass
defdecorator(self):def inner(*args, **kwargs):print('before')
self(*args, **kwargs)print('after')returninner
@decoratordeftest1(self):print('我被執行了')classFoo2(Foo):
@Foo.decorator#執行被繼承的方法
defdecorator(self):print('執行被繼承的方法開始')
super(Foo2, self).test1()#運行Foo2父類Foo的test1方法
print('執行被繼承的方法結束')
foo=Foo()
foo.test1()print('-----')
foo2=Foo2()
foo2.decorator()
#實例
classTest1(object):defdecorator1(self):def inner(*args, **kwargs):
self(*args, **kwargs)print('n年前添加的附加功能')returninner
@decorator1deftest1(self):print('n年前實現的某個功能')classTest2(Test1):defdecorator2(self):def inner(*args, **kwargs):
self(*args, **kwargs)print('今天添加的附加功能')returninner
@decorator2deftest2(self):
super(Test2, self).test1()print('昨天自己實現的功能')
foo=Test2()
foo.test2()
View Code
#通過類中的裝飾器實現,獲取對象方法的實例屬性defmod_test(cls):#返回修改的類
defdecorator(fun):#返回裝飾函數
defnew_fun(self):print(self.before)print(fun(self))print(self.after)returnnew_fun
cls.test=decorator(cls.test)returncls
@mod_testclassFoo(object):def __init__(self):
self.before= "before"self.after= "after"
deftest(self):return "testing"foo=Foo()
foo.test()
python迭代器
l = [1,2,3,4,5,6]print(l.__iter__()) #iter(l)這兩者是一樣的,都返回了一樣迭代器對象
d =(iter(l))print((next(d)))#返回 1
print((next(d)))#返回 2#所以生成器本身就是迭代器
#for循環本身主要做的三件事:
for i in [1,2,34,5,5]:#1.
iter([1,2,34,5,5])#調用可迭代對象的iter方法返回一個迭代器對象#2.調用迭代器對象的next方法#3.處理Stoplteration
#校驗
from collections importIterator,Iterable#Iterable 迭代器#Iterator 迭代對象
print(isinstance([1334],list))#判斷給對象是否為一個list,返回布爾值
print(isinstance(l,Iterable))#判斷是否是迭代對象,返回布爾值
自定義迭代器
classMytest:def __init__(self, len):
self.index=0
self.len=lendef __iter__(self):returnselfdef __next__(self):if self.index
self.index+= 1
returnself.indexraiseStopIterationfor i in Mytest(20):print(i)#打印1-20,迭代器底層調用,結構復雜
python生成器
用法1:
f = (x for x in range(1000))#使用列表生成式外面套了一層中括號并賦值給f對象
print(f)#此時f打印的就是一個生成器對象 at 0x0000000001DD79E8>#此時需要打印x必須如下方式,生成器就像一位廚師,做出x就是一盤盤菜,每一盤菜必須吃完再吃第二盤,而且不能跳著吃,倒著吃
print(next(f))#調用使用next()比較常見
print(next(f))print(next(f))print(f.__next__())#f.__next__()也是可以的 py2的調用方式是f.next直接調用
print(f.__next__())print(f.__next__())
用法2:
#yield也是生成器中的例子,如果在沒有使用next(),函數根本不會被執行,調用每一次程序會檢測yield如果有,yield包括后面的代碼不會執行,直到下次調用才執行下次的,所以函數中只要有yield就是生成器#yield可以理解成return
deftest(len):print(len,'11')yield 1
print(len,'222')yield 2
print(len,'333')
test('1')#此函數不會被調用
for i in test('1'):#for內置有生成器next,可以對生成器對象一直使用next(n)
print(i,'調用')#打印#1 11#1 調用#1 222#2 調用#1 333#這個就是異步io的原理了,python里面的協程基于yield實現
#生成器的好處:#如果我們寫一個 danger = [x for x in range(9999999999999999999)]#當我們打印danger時我們的電腦會在內存中放置0-n的數據,造成內存不足,死機的情況,生成器的出現會把舊變量替換成新變量,從而不會造成大數據所產成內存泄露的問題
nodanger = (x for x in range(999999999999999999999999))print(next(nodanger))
協程
簡單的說只要能夠完成多任務切換的都是協程,規避io操作是協程體現出的效果
yield是協程最底層的使用方法
#yield的使用
deff():print('jjjj')yield 1
print('gggg')yield
print(f())#創建一個生成器對象,但是函數不會執行
gen=f()#next(gen)#執行生成器對象
gen.send(None)
x= gen.send(10)#next(gen)這兩者是一樣的
print(x)
gevent模塊
#gevent模塊 在gevent中主要模式就是greenlet,它是c擴展的輕量級協程
from greenlet importgreenletdeftest1():print('111')
b.switch()print('333')
b.switch()deftest2():print('222')
a.switch()print('444')
a= greenlet(test1)#創建一個生成器對象
b =greenlet(test2)
a.switch()
#from gevent import monkey#monkey.patch_all()#實時監聽io堵塞,效果顯著,要注意的是這兩句話要放到最上面不然就會報錯,我也不知道為什么
importgeventdeftest3():print('模擬io堵塞1')
gevent.sleep(1)#模擬堵塞時間
print('堵塞消除1')deftest4():print('模擬io堵塞2')
gevent.sleep(2)print( '堵塞消除2')
gevent.joinall([gevent.spawn(test3),gevent.spawn(test4)])#joinall效果是如果兩個方法中其中一個出現io堵塞,會跳到另外一個方法,如果都堵塞都會等著,直到io堵塞消除#優勢:io堵塞的時間取決于io堵塞最長的時間,提升效率
協程實例:
from gevent importmonkey
monkey.patch_all()
#gevent模塊 #基于greenlet封裝,避免多線程切換導致io執行效率降低
importgeventimportrequestsdefrun(name, url):
r=requests.get(url)
open(name+ '.html', 'wb').write(r.content)
url= {'rainbol01': 'https://www.cnblogs.com/RainBol/','rainbol02': 'https://www.cnblogs.com/RainBol/p/9505438.html','rainbol03': 'https://www.cnblogs.com/RainBol/p/10077388.html'}for name, url inurl.items():
g= gevent.spawn(run, name, url) #啟動
g.join() #等待并切換
#阻塞等待分配任務完成后結束#l = []#for i in range(10):#g = gevent.spawn(run,name,url)#l = g.append(g)#g.joinall(l)
版權聲明:本文原創發表于 博客園,作者為?RainBol本文歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則視為侵權。
總結
以上是生活随笔為你收集整理的python的装饰器、迭代器、yield_python装饰器,迭代器,生成器,协程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: fasterrcnn tensorflo
- 下一篇: jmeter mysql查询结果提取_J