【Python基础】Python 流程控制专题总结
今天流程控制專題?流程控制與代碼的執行順序息息相關,流程控制相關的關鍵字,如if,elif,for,while,break,continue,else,return,yield,pass等。
本專題詳細總結與流程控制相關的基礎和進階用法,大綱如下:
基礎用法
1 if 用法
2 for 用法
3 while,break,continue
進階用法
4 for 使用注意
5 range 序列
6 Python特色:循環與else
7 pass 與接口
8 return 和 yield
9 短路原則
總結
基礎用法
專題的開始,先總結與流程控制相關的基礎用法。
1 if 用法
if 對應邏輯控制的條件語句,它的基本結構可以表示為:如果滿足某個條件,則怎么怎么樣。
如下函數maxChunksToSort中,如果滿足當前數組nums的索引i等于區間[0,i]的最大值,則[0,i]區間能被分割為一個Chunk.
def?maxChunksToSort(nums):maxn,?count?=?nums[0],?0for?num?in?nums:maxn?=?max(maxn,?num)if?i?==?maxn:count?+=?1return?countif后的語句指定了一個條件,若滿足if則,:后的語句成立。
如果if不滿足,再使用elif判斷其他情況,可以一直寫elif,若是最后一個判斷條件,可使用else,其基本結構為:
if?A:print('condition?A?meets') elif?B:print('condition?B?meets') elif?C:print('condition?C?meets') else:print('other?conditions?meets')2 for 用法
Python的for除了具備控制循環次數外,還能直接迭代容器中的元素。
控制循環次數:
for?i?in?range(1,?len(nums)):print(i)還能直接操作容器內的元素:
a?=?[1,?[2,?4],?[5,?7]] for?item?in?a:print(item)3 while,break,continue
while后面緊跟一個判斷條件,若滿足條件則會一直循環,直到不滿足條件時退出。但這不是絕對的,如果while后的語句塊內含有break,即便條件依然滿足,但遇到break也會一樣退出。
如下檢測輸入是否為整數,直到輸入整數時,執行break退出while循環:
while?True:a?=?input('please?input?an?Integer:?')try:ai?=?int(a)print('輸入了一個整數?%d?,input?結束'?%?(ai,))breakexcept:print("%s?isn't?a?Integer"?%?(a,))做如下測試:
please?input?an?Integer:?1.2 1.2?isn't?a?Integer please?input?an?Integer:?1 輸入了一個整數?1?,input?結束continue與最近的循環語句for或while組合,表示接下來循環體內的語句不執行,重新進入下一次遍歷。
def?f(nums):for?num?in?nums:if?num?<=?0:continueprint('得到一個大于0的數?%d'?%?(num,))做如下測試:
得到一個大于0的數?2 得到一個大于0的數?4進階用法
基礎用法保證我們能夠應付日常遇到的基本的代碼流程,不過要想進一步深入理解Python特色的、與順序相關的執行功能,還需要理解下面的進階用法。
4 for 使用注意
for 語句遍歷容器類型或可迭代類型時,如果涉及到增加、刪除元素,就需要小心。比如請先看下面的例子:
刪除列表中的某個元素值,可能有重復,要求元素順序不變,空間復雜度為O(1),如果像下面這樣寫就會有問題:
def?delItems(nums,?target):for?item?in?nums:if?item?==?target:nums.remove(item)return?nums對于大多數情況,上面的代碼無法暴露出bug。但是考慮下面輸入(特點:被刪除的值連續出現):
r?=?delItems([2,?1,?3,?1,?1,?3],?1) print(r)打印結果為:[2,3,1,3]
對于剛接觸編程的朋友對此很不解,為什么其中一個1未被remove.
不管是Python, Java, C++,列表或數組刪除元素時,其后面的元素都會逐次前移1位,但是for依然會正常迭代,因此“成功”規避了相鄰的后面元素1.
圖形解釋命中目標后的一系列動作:
上面的列表命中目標刪除元素1下步最關鍵:解釋器自動前移刪除位置后的所有元素
但是,等到下一次迭代時,迭代器不等待,正常移動到下一個位置:
這樣元素3成功逃避是否與目標值相等的檢查。
結論:命中目標處的后一個位置都逃避了是否與目標值相等的檢查,所以一旦有連續目標值,必然就會漏掉,進而觸發上面的bug.
明白上面這個原因后,重新再改寫一遍刪除所有重復元素的代碼,下面代碼不再使用for直接遍歷元素(再說一遍:增刪元素原來迭代器發生改變,所以會導致異常行為),而是使用索引訪問:
def?delItems(nums,?target):i?=?0while?i?<?len(nums):if?nums[i]?==?target:del?nums[i]i?-=?1i?+=?1return?numsr?=?delItems([2,?1,?3,?1,?1,?3],?1) print(r)?#?[2,3,3]如果元素等于target,從數組nums中刪除nums[i],刪除后解釋器自動將i后的元素都前移1位。據此,巧妙的控制i值,一旦命中立即i減去1,這樣確保不漏檢查。
5 range 序列
range在Python中經常用于生成一串數字序列,對剛入門Python的朋友想嘗試打印其中的值:
In?[3]:?print(range(10)) range(0,?10)要想看到每個值可與for結合:
In?[21]:?for?i?in?range(10):...:?????print(i,end=",")...: 0,1,2,3,4,5,6,7,8,9,那么有的朋友不禁要問range函數的返回值為什么能與for結合?
類型為Iterable的對象都可與for結合,下面確認range(10)返回值是否為Iterable:
In?[13]:?from?collections.abc?import?Iterable In?[14]:?isinstance(range(10),Iterable) Out[14]:?True?#?它是?Iterable?類型它為什么不是一次全部輸出一個列表,就像下面這樣:
In?[23]:?list(range(10)) Out[23]:?[0,?1,?2,?3,?4,?5,?6,?7,?8,?9]而是要一個一個的輸出?
range函數為了高效節省內存,一次只返回一個值,而不是直接將構成序列的全部元素加載到內存。
Python里的range不支持創建浮點序列,所以為了更加清楚的展示range的原理,編寫一個創建浮點數的序列frange:
def?frange(start,?stop,?step):i?=?startwhile?i?<?stop:yield?ii?+=?step代碼只有幾行,yield作為控制流程的一個關鍵字,下面我們會詳細說到。
使用frange:
fr?=?frange(0,?1.,0.2) for?i?in?fr:print("{:.2f}".format(i),end=",")打印結果如下,得到一個差值為0.2的等差數列:
0.00,0.20,0.40,0.60,0.80,6 Python特色:循環與else
6.1 for能和else組對
Python一大特色:while,for能和else組對,不僅如此,try except和else也能組對,下面介紹它們存在的價值。
找出2到15的所有素數,如果不是素數打印出一對因子,實現代碼如下:
for?num?in?range(2,?16):is_prime?=?True?for?item?in?range(2,?num):if?num?%?item?==?0:print('%d?=?%d*%d?'?%?(num,?item,?num?//?item))is_prime?=?Falsebreakif?is_prime:print("%d?is?prime"?%?(num))打印結果如下:
2?is?prime 3?is?prime 4?=?2*2 5?is?prime 6?=?2*3 7?is?prime 8?=?2*4 9?=?3*3 10?=?2*5 11?is?prime 12?=?2*6 13?is?prime 14?=?2*7 15?=?3*5使用is_prime標志位判斷是否找到num的一對因子,若都遍歷完仍無發現則打印此數是素數。
這是我們比較熟悉的常規解決思路,但是如果使用for和else組對,它的價值便能體現出來:
for?num?in?range(2,?16):for?item?in?range(2,?num):if?num?%?item?==?0:print('%d?=?%d*%d?'?%?(num,?item,?num?//?item))breakelse:print("%d?is?prime"?%?(num))上面代碼實現同樣的功能,但代碼相對更加簡潔。通過前后代碼對比,我們便能看出for和else組對的功能:for遍歷完成后執行else,但是觸發break后,else不執行。
大家平時多多使用,便能習慣以上用法。通過上面的對比,我們也能直觀的感受到它們的價值。
6.2 try,except 和 else 組對
try 和 except 組對比較容易理解,觸發異常執行 except 里的代碼,否則不執行。
但是加上一個else實現怎樣的作用呢?
首先看下面的例子:
In?[9]:?while?True:...:?????try:...:?????????a?=?int(input('請輸入一個整數:?'))...:?????except?ValueError:...:?????????print('input?value?is?not?a?valid?number')...:?????else:...:?????????if?a?%?2?==?0:...:??????????????print('輸入的?%d?是偶數'?%(a,))...:?????????else:...:?????????????print('輸入的?%d?是奇數'?%(a,))...:?????????break測試:
請輸入一個整數:?t input?value?is?not?a?valid?number 請輸入一個整數:?5 輸入的?5?是奇數try 保護的代碼正常通過后,else才執行。
有的朋友會問,為什么不把else這塊代碼放到try里面?這還是有一定區別的:放到else中意味著這塊代碼不必受保護,因為它不可能觸發ValueError這樣的異常。
7 pass 與接口
Python中最特別的關鍵字之一便是pass,它放在類或函數里,表示類和函數暫不定義。
class?PassClass:passdef?PassFun():pass?如上實現最精簡的類和函數定義。
今天跟大家分享一個pass的特別有用的用法,尤其對Java語言的interface,implements等較熟悉的朋友,在Python中也能實現類似寫法。
首先安裝一個包:
pip?install?python-interface下面是這個包的基本用法,首先創建一個接口類:
from?interface?import?implements,?Interfaceclass?MyInterface(Interface):def?method1(self,?x):passdef?method2(self,?x,?y):pass下面實現接口:
class?MyClass(implements(MyInterface)):def?method1(self,?x):return?x?*?2def?method2(self,?x,?y):return?x?+?y這個包對熟悉Java語言的朋友還是非常實用,接口和實現類用法,可以平穩過渡到Python語言中。
8 return 和 yield
程序遇到 return 和 yield 都是立即中斷返回。那么yield和return又有什么不同呢?
與return不同,yield中斷返回后,下一次迭代會進入到yield后面的下一行代碼,而不像return下一次執行還是從函數體的第一句開始執行。
用圖解釋一下:
遇到yield中斷返回第一次 yield 返回 1
第二次迭代,直接到位置2這句代碼。
然后再走for ,再yield,重復下去,直到for結束。
以上就是理解yield的重要一個點,當然yield還會與from 連用,還能與send實現協程等,這些都放在后面的專題。
9 短路原則
最后以一個有意思的短路問題結束流程控制專題。
布爾運算符 and 和 or 也被稱為短路運算符:它們的參數從左至右解析,一旦可以確定結果解析就會停止。
Python中的短路運算符常見的有兩個:and , or
A and B : 如果 A 不成立,B 不會執行
A or B : 如過 A 成立,B不會執行
所以被稱為短路運算符
舉幾個例子一看就明白,請看下面代碼:
代碼1:
a?=?'' b?=?a?and?'i?will?not?execute' print(b)打印結果為空,因為and運算符從左到右檢查,一旦a為空即為假,則結果已確定為假,'i will not execute'被短路。
代碼2:
a?=?'python' b?=?a?or?'i?will?not?execute' print(b)打印結果為:python,因為or運算符從左到右檢查,一旦a為真則結果已確定為真,所以'i will not execute'被短路。
總結
本專題細致總結了流程控制的基礎和進階用法,具體包括以下:
基礎用法
1 if 用法
2 for 用法
3 while,break,continue
進階用法
4 for 使用注意
5 range 序列
6 Python特色:循環與else
7 pass 與接口
8 return 和 yield
9 短路原則
總結
《end》
總結
以上是生活随笔為你收集整理的【Python基础】Python 流程控制专题总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【论文解读】打破常规,逆残差模块超强改进
- 下一篇: 【机器学习基础】浅谈为什么L2正则化有效