学习笔记(11月03日)
三周五次課(11月3日)
1.生成式和生成器
1.1列表生成式是python受歡迎的語法之一,通過一句簡潔的語法就可以對一組元素進行過濾,還可以對得到的元素進行轉換處理。
語法格式為:
[exp for val in collection if condition]
相當于
result?=?[] for?val?in?collection:if?(condition):result.append(exp)例子:
結果:
<type?'list'> [0,?4,?16,?36,?64]解釋:
1,以此取出xrange(10)從0到9的數字
2,判斷x*x是偶數,就保留,存在新的字典中
3,把所有符合x*x是偶數的元素都放到新的列表中返回
? ? 通過列表生成式,我們可以直接創建一個列表。但是,受到內存限制,列表容量肯定是有限的。而且,創建一個包含100萬個元素的列表,不僅占用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那后面絕大多數元素占用的空間都白白浪費了。
? ? 所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環的過程中不斷推算出后續的元素呢?這樣就不必創建完整的list,從而節省大量的空間。在Python中,這種一邊循環一邊計算的機制,稱為生成器(Generator)。
? ? 生成器是一次生成一個值的特殊類型函數。可以將其視為可恢復函數。調用該函數將返回一個可用于生成連續 x 值的生成器【Generator】,簡單的說就是在函數的執行過程中,yield語句會把你需要的值返回給調用生成器的地方,然后退出函數,下一次調用生成器函數的時候又從上次中斷的地方開始執行,而生成器內的所有變量參數都會被保存下來供下一次使用。
? ? 要創建一個generator,有很多種方法。第一種方法是把一個列表生成式的[]改成(),就創建了一個generator:
例子:
結果:
<type?'generator'> 0 4 aaaaaaa 16 36 64解釋:
generator保存的是算法,每次調用next(),就計算出下一個元素的值,直到計算到最后一個元素為止
? ? 1.2 定義generator的另一種方法。如果一個函數定義中包含yield關鍵字,那么這個函數就不再是一個普通函數,而是一個generator:
在了解這個方法之前,我們先來看一個小例子,更好的幫助你理解yield的使用
def?fib(n):sum?=?0i?=?0while?(i?<?n):sum?=?sum?+?ii?+=?1print(sum)fib(10)結果:
解釋:
這個程序很簡單,就是求0到9所有數字之和,接下來,我們只要稍微改動一下,你看看有什么差別
def?fib(n):sum?=?0i?=?0while?(i?<?n):sum?=?sum?+?ii?+=?1yield?sumfor?x?in?fib(10):print(x) print(type(fib(10)))結果:
0 1 3 6 10 15 21 28 36 45 <type?'generator'>? ? 結果和上面的結果是一樣的,但是有什么不同呢,簡而言之,包含yield語句的函數會被特地編譯成生成器。當函數被調用時,他們返回一個生成器對象,這個對象支持迭代器接口。每當遇到yield關鍵字的時候,你可以理解成函數的return語句,yield后面的值,就是返回的值。但是不像一般的函數在return后退出,生成器函數在生成值后會自動掛起并暫停他們的執行和狀態,他的本地變量將保存狀態信息,這些信息在函數恢復時將再度有效,下次從yield下面的部分開始執行。
解釋:
1,因為以上函數有關鍵字yield,所以生成的是一個生成器。
2,通過for循環調用生成器,當執行到yield的時候,返回sum的值,sum為0,此時暫停并記錄sum的值
3,打印sum的值,然后繼續往下執行。此時跳入下一個循環while(1<10)
4,直到遇到yield的時候,返回sum的值。
5,反復執行3,4步驟,直到循環結束,最終程序退出
二者的區別很明顯:
一個直接返回了表達式的結果列表, 而另一個是一個對象,該對象包含了對表達式結果的計算引用, 通過循環可以直接輸出
生成器不會一次性列出所有的數據,當你用到的時候,再列出來,更加節約內存的使用率。
2.迭代器
Iterable(可迭代對象)和Iterator(迭代器)主要區別是:
凡是可以用for 循環的都是Iterable(可迭代對象),凡是需要通過next()函數獲得值的可迭代對象都是 Iterator(迭代器)。
? 所以生成器可以被next()函數調用并不斷返回下一個值的對象稱為迭代器)(可以簡單理解為生成器就是迭代器的可迭代對象)
凡是可作用于for循環的對象都是Iterable類型;
凡是可作用于next()函數的對象都是Iterator類型,它們表示一個惰性計算的序列;
3.裝飾器
? ? 裝飾器本質上是一個Python函數,它可以讓其他函數在不需要做任何代碼變動的前提下增加額外功能,裝飾器的返回值也是一個函數對象。它經常用于有切面需求的場景,比如:插入日志、性能測試、事務處理、緩存、權限校驗等場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量與函數功能本身無關的雷同代碼并繼續重用。概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能。
簡單裝飾器
? ? 函數use_logging就是裝飾器,它把執行真正業務方法的func包裹在函數里面,看起來像bar被use_logging裝飾了。在這個例子中,函數進入和退出時 ,被稱為一個橫切面(Aspect),這種編程方式被稱為面向切面的編程(Aspect-Oriented Programming)。
@符號是裝飾器的語法糖,在定義函數的時候使用,避免再一次賦值操作
def?use_logging(func):def?wrapper(*args,?**kwargs):logging.warn("%s?is?running"?%?func.__name__)return?func(*args)retrunwrapper@use_logging def?foo():print("i?am?foo")@use_logging def?bar():print("i?am?bar")bar()? ? 如上所示,這樣我們就可以省去bar = use_logging(bar)這一句了,直接調用bar()即可得到想要的結果。如果我們有其他的類似函數,我們可以繼續調用裝飾器來修飾函數,而不用重復修改函數或者增加新的封裝。這樣,我們就提高了程序的可重復利用性,并增加了程序的可讀性。
? ? ? 裝飾器在Python使用如此方便都要歸因于Python的函數能像普通的對象一樣能作為參數傳遞給其他函數,可以被賦值給其他變量,可以作為返回值,可以被定義在另外一個函數內。
練習題:用函數實現9*9乘法口訣
for?i?in?range(1,?10):for?j?in?range(1,?i?+?1):print?j,?'*',?i,?'=',?i?*?j,?'?',print("")結果:
1?*?1?=?1??? 1?*?2?=?2???2?*?2?=?4??? 1?*?3?=?3???2?*?3?=?6???3?*?3?=?9??? 1?*?4?=?4???2?*?4?=?8???3?*?4?=?12???4?*?4?=?16??? 1?*?5?=?5???2?*?5?=?10???3?*?5?=?15???4?*?5?=?20???5?*?5?=?25??? 1?*?6?=?6???2?*?6?=?12???3?*?6?=?18???4?*?6?=?24???5?*?6?=?30???6?*?6?=?36??? 1?*?7?=?7???2?*?7?=?14???3?*?7?=?21???4?*?7?=?28???5?*?7?=?35???6?*?7?=?42???7?*?7?=?49??? 1?*?8?=?8???2?*?8?=?16???3?*?8?=?24???4?*?8?=?32???5?*?8?=?40???6?*?8?=?48???7?*?8?=?56???8?*?8?=?64??? 1?*?9?=?9???2?*?9?=?18???3?*?9?=?27???4?*?9?=?36???5?*?9?=?45???6?*?9?=?54???7?*?9?=?63???8?*?9?=?72???9?*?9?=?81轉載于:https://blog.51cto.com/13406610/1978766
總結
以上是生活随笔為你收集整理的学习笔记(11月03日)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux中main是如何执行的
- 下一篇: 【JAVA零基础入门系列】Day14 J