摘要:也就是給原函數加個外殼。類裝飾填充了啊我是原函數類裝飾填充了啊我是原函數說明后面關于類的裝飾器如果理解困難當做了解即可,用的也少。
可迭代對象、生成器、迭代器三者的關系
1. 迭代器一定是可迭代對象 2. 生成器是迭代器的一種 3. 可迭代對象:必須實現 __iter__方法 4. 迭代器:必須實現 __iter__方法 和 __next__ 方法 5. 生成器:必須實現 __iter__方法 和 __next__ 方法,yield 代替了這兩個方法 6. 工具包: from collections import Iterable,Iterator 7. 查看抽象接口: In [265]: Iterable.__abstractmethods__ Out[265]: frozenset({"__iter__"}) In [266]: Iterator.__abstractmethods__ Out[266]: frozenset({"__next__"}) 8. 可迭代對象都可以被 for循環 所遍歷, 另外 實現了 __getitem__的類 其對象也可for遍歷 關于 __getitem__等魔法方法,以后會多帶帶寫一篇文章。生成器
生成器有兩種寫法: 形式一: In [230]: def f(): ...: for x in range(10): ...: yield x In [231]: y = f() 形式二: In [239]: y = ( x for x in range(10) ) In [240]: y Out[240]:迭代器at 0x0000024A4D3AFB48> "推動生成器" 迭代有三種方式: 方式1: In [232]: next(y) Out[232]: 0 方式2: In [233]: y.__next__() Out[233]: 1 方式3: In [236]: y.send(None) Out[236]: 2 前兩種方式是等價的,第三種方式有些差別,且聽我說: In [248]: def f(): ...: print(1) ...: a = yield 2 ...: print(a) In [249]: y = f() In [250]: y.send(None) 1 # 這里是 print(1)的結果 Out[250]: 2 In [251]: y.send(100) 100 # 這里是print(a)的結果 不知道閣下能否看出和兩種的差別: 1. yield 2 # 這行多了個賦值操作 2. send(100) # send() 函數里面放了個,然后print(a) 打印的就是100 舉個例子: 1. a = yield 2 # 相當于一個士兵等待指令,等號左邊還未執行,程序就被封鎖了 2. send(100) # 長官輸入了一個100,士兵收到后就把程序解封,并執行等號左邊 3. 于是 就相當于 a 被賦值為 100
先看兩個簡單的函數: In [294]: iter([1,2,3]) Out[294]:裝飾器In [295]: reversed([1,2,3]) Out[295]: 自定義迭代器: In [283]: class A(Iterator): # 注意這里:繼承了Iterator就不用實現 __iter__接口了 ...: def __init__(self, value): ...: self.value = value ...: self.index = -1 ...: def __next__(self): # 注意這里:__next__是寫邏輯的主要接口,每次返回單個值 ...: self.index += 1 ...: return self.value[self.index] In [284]: a = A(["Tom", "Jerry"]) In [285]: next(a) Out[285]: "Tom" In [286]: next(a) Out[286]: "Jerry" 串聯合并迭代器: 1. 普通序列迭代器串聯 In [287]: from itertools import chain In [289]: chain(range(1),range(2),range(3)) Out[289]: In [290]: list(chain(range(1),range(2),range(3))) Out[290]: [0, 0, 1, 0, 1, 2] 2. 字典序列迭代器串聯 In [288]: from collections import ChainMap In [291]: ChainMap({1:1},{2:2,3:3}) Out[291]: ChainMap({1: 1}, {2: 2, 3: 3}) In [292]: dict(ChainMap({1:1},{2:2,3:3})) Out[292]: {1: 1, 2: 2, 3: 3}
裝飾器如果按鉆牛角尖的方式來理解的確是很頭疼的事情。先說個例子吧: In [296]: def f(func): ...: def f1(): ...: print("原函數之前加點功能") ...: func() # 這就是原函數 ...: print("原函數之后加點功能") ...: return f1 In [299]: @f #這句等價于=> func = f(func) ...: def func(): ...: print("我是原函數哦") In [300]: func() >> 原函數之前加點功能 >> 我是原函數哦 >> 原函數之后加點功能 解釋 用大白話來講,裝飾器就是在原函數的前后加功能。也就是給原函數加個外殼。看上去是調用的原函數, 實則調用的是外殼函數,外殼函數里面包括原函數和 一些其他的自定義功能 例子: 面包不好吃啊,但是你還想吃這個面包,咋整? 上下抹點奶油,就變成了三明治(我沒吃過。。) 吃其他面包的時候繼續抹上奶油就行了(封裝性) 面包-原函數 三明治-被裝飾器裝飾后的函數 各種功能(吃法)快速拼接: @奶油 def 面包1(): pass @奶油 def 面包2(): pass @沙拉 def 面包1(): pass @沙拉 def 面包2(): pass 存在問題: @f #這句等價于=> func = f(func) 這是我上面說過的一句話,你仔細看看: func之前指向的是(原函數)面包的空間,恩,func函數名 也就是(__name__) 是func(面包) 現在他指向的是(新函數)三明治的空間,恩,它的函數名是f1(三明治) 函數名變了,有些張冠李戴的感覺,如果不想讓它變,并保持本身的函數名,看我操作: In [301]: from functools import wraps In [316]: def f(func): ...: @wraps(func) ### 沒錯 這里是最主要的,基本格式固定寫法,照著寫即可 ...: def f1(): ...: print(func.__name__) ...: print("原函數之前加點功能") ...: func() ...: print("原函數之后加點功能") ...: return f1 標準裝飾器使用(原函數帶有返回值 和 參數): In [323]: def f(func): ...: @wraps(func) ...: def f1(*args, **kwargs): ...: print("報年齡和性別~~~") ...: return func(*args, **kwargs) ...: return f1 In [324]: @f #每次都要記住 test=f(test) 這個隱含的變形,熟了就好了 ...: def test(name,age): ...: print(name, age) In [325]: test("Tom",18) -------------------------------下面是打印部分 報年齡和性別~~~ Tom 18 帶參數的裝飾器: 構造如下: def foo(arg): # 其實就是在原來的基礎上再再再次包裝個外殼,僅此而已 # 之前講的裝飾器f實現代碼原封不動全放在這里面,看下面幫你寫好了。 def f(func): @wraps(func) def f1(*args, **kwargs): return func(*args, **kwargs) return f1 return f 調用形如: @foo("123") #多了個參數,可分解為foo的返回值f 放在 @ 的后面,是不是一切又回到了從前? def func(): pass 裝飾類: 應用場景: Python WEB框架 Flask/Django都有 FBV和CBV模式 (以后我也會寫這方面的文章) FBV: Function Based View 簡單來說,邏輯視圖用函數來寫 ----那么需要裝飾器的時候,直接用普通函數裝飾器裝飾到函數上即可 CBV: Class Based View 簡單來說,邏輯視圖用類來寫 ----這種沒有函數,是用類寫的,那么這時候就需要對類進行裝飾了 核心思想: 還是記住上面講的隱式變形,只不過這次傳給裝飾器的是類,對類的操作可就太多了。 里面一大堆黑魔法,下面我就來寫一下類初始化功能性裝飾器。(以后也會多帶帶寫黑魔法的文章) In [1]: def f(c): def f1(*args, **kwargs): return c(*args,**kwargs) return f1 In [2]: @f ...: class A: ...: def __init__(self,name): ...: print(name) In [3]: A("Tom") Tom # 這是print打印的輸出 Out[3]: <__main__.A at 0x2948e8fb828> 類裝飾器: 這個場景真沒遇到過,不過實現也很容易的。 In [8]: class A: ...: def __init__(self,func): ...: self.func = func ...: def __call__(self,*args,**kwargs): ...: print("類裝飾填充了啊") ...: self.func(*args, **kwargs) ...: In [9]: @A ...: def test(): ...: print("我是原函數") ...: In [10]: test() 類裝飾填充了啊 我是原函數 說明:后面關于類的裝飾器如果理解困難當做了解即可,用的也少。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43829.html
摘要:解釋就相當于把每個序列元素的每一個單獨用一個管道函數處理,再把他們按順序組合成一個新可迭代對象注意這個管道函數只能是單參數函數,如果想傳遞多個參數怎么辦使用偏函數怕有些人看不懂,這里就不用了,而是用普通函數定義方式固定值固定值固定值固定值固 map In [25]: list(map(lambda a:a**2, [1,2,3,4])) Out[25]: [1, 4, 9, 16] 解...
摘要:不要疑惑,告訴你答案這個代表正負號的正。雖然一點技術含量沒有,但是你要懂序列也許叫可迭代對象更為合適,但是我喜歡叫序列。 數據結構 可變類型與不可變類型(重頭戲) 基操: 可變類型:[], {} # 可增刪改 查 不可變類型: int float str () # 無法增刪改, 只可查 升操: + 與...
摘要:多線程對于爬蟲方面也可以表現出較好的性能。計算密集型就別想多線程了,一律多進程。所以同一時刻最大的并行線程數進程數的核數這條我的個人理解很模糊,參考吧多線程多線程有種通過的那種方式,非常普遍,此處就不寫了。 GIL的理解 GIL這個話題至今也是個爭議較多的,對于不用應用場景對線程的需求也就不同,說下我聽過的優點: 1. 我沒有用過其他語言的多線程,所以無法比較什么,但是對于I/O而言,...
摘要:類的繼承類繼承有三種調用方式,其實是有區別的,聽我慢慢道來第一種父類方法參數直接調用第二種方法參數直接調用在誰的類下調用,就找此類對應的下一個就是要繼承的第三種方法參數找類名對應的的下一個,就是繼承的,一般寫本身的類名上下文管理器上下文管理 類的繼承 類繼承有三種調用方式,其實是 有區別 的,聽我慢慢道來 class A: def say(self, name): ...
預編譯 import re re1 = re.compile(r元字符 組成的正則規則) # 元字符下面會說 re1.方法() # 方法下邊也會說 元字符: 表示普通字符: . # 除了 外 都可以匹配的到 d # 只匹配 純數字 0-9 D # 和 d相反, 除了數字全都匹配 ...
閱讀 2067·2019-08-30 15:53
閱讀 3064·2019-08-30 15:44
閱讀 2914·2019-08-30 14:11
閱讀 2910·2019-08-30 14:01
閱讀 2694·2019-08-29 15:16
閱讀 3719·2019-08-29 13:10
閱讀 1239·2019-08-29 10:56
閱讀 2526·2019-08-26 13:58