iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 7
0
Software Development

從零開始學Python系列 第 7

[Day 07] 從零開始學Python - 程式結構與流程語法:如果對手太弱太簡單,那不是很爽嗎?(上)

註:本文同步刊載在Medium,若習慣Medium的話亦可去那邊看呦!

先來解答昨天的問題吧!

  1. 李嚴的是炸鳳尾蝦,劉昴星的是雲龍炸蝦,
    如同上一篇所提到的,字典的value是可以是list的!
  2. 按照步驟,前三個問題要取liu-lee, lee-liu, lee & liu,
    後面將set加進新的key後再替代回原本shrimp['炸鳳尾蝦']。
>>> shrimp = {'炸鳳尾蝦':['蝦子','核果','油'],'雲龍炸蝦':['蝦子','核果','油','豆皮','醬汁']}
>>> lee = set(shrimp['炸鳳尾蝦'])
>>> liu = set(shrimp['雲龍炸蝦'])
>>> lee # 所以我說那個醬汁呢?
{'核果', '油', '蝦子'}
>>> liu
{'醬汁', '蝦子', '豆皮', '核果', '油'}
>>> liu-lee
{'豆皮', '醬汁'}
>>> lee-liu # 李嚴沒有多用到的東西
set()
>>> lee & liu # 都用到的材料
{'核果', '油', '蝦子'}
>>> lee.add('蘋果', '洋蔥','醬汁') # set不能夠一次add多個key,除了一個一個加以外,也可以用update()方法。(lee.update(['蘋果', '洋蔥','醬汁']))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: add() takes exactly one argument (3 given)
>>> lee.add('蘋果')
>>> lee.add('洋蔥')
>>> lee.add('醬汁')
>>> lee
{'洋蔥', '醬汁', '蝦子', '蘋果', '核果', '油'}
>>> lee-liu
{'洋蔥', '蘋果'}
>>> shrimp['炸鳳尾蝦'] = list(lee)
>>> shrimp
{'炸鳳尾蝦': ['洋蔥', '醬汁', '蝦子', '蘋果', '核果', '油'], '雲龍炸蝦': ['蝦子', '核果', '油', '豆皮', '醬汁']}
  1. 按照題目要求一個一個來就可以了,請留意index的初始値是0這點呦!
>>> lt = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> lt1 = lt[::2]
>>> lt2 = lt[1::2]
>>> lt1, lt2
([1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
>>> lt1.extend(lt2)
>>> lt1
[1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
>>> del lt1[7]
>>> lt1
[1, 3, 5, 7, 9, 2, 4, 8, 10]
>>> del lt1[1]
>>> lt1
[1, 5, 7, 9, 2, 4, 8, 10]
>>> lt1.sort()
>>> lt1
[1, 2, 4, 5, 7, 8, 9, 10]

接下來,讓我們來介紹今天的主題:程式結構與流程語法。
在這篇文章中,我們要來介紹一些超級無敵常用的東西,
常用到基本上天天會遇到的那種。

首先是程式結構。
我們應該在前幾篇文章中有提到過,在Python中當需要執行的東西比較多時,
我們是可以將一整段寫在一個.py檔案裡,再用python xxx.py的方式去執行,對吧!
在之後的程式裡,如果程式碼比較多比較複雜,
建議讀者先將程式規劃好打在檔案內,再進行執行,可以避免打錯造成的一些麻煩。

先來談談註解,註解通常使用**「#」的符號,
基本上意味著
一行程式碼在這個符號後面的任何東西都不會有影響。(且只影響該行)
(但是擺在字串內的話就不會有註解的效果,會被當成普通的字元)
通常狀況下,在文字編輯器內將想註解的行框起來,再按
Ctrl+/**,
編輯器會自動幫助你將這幾行都註解起來。
如果要多行註解的話,也可以在行的最前面使用''' (三個單引號),
註解結束的位置同樣放置'''。
(但這種註解一般被視為在為函式(後面會提到)打說明文件用的文字,稱之為文件字串(docstring),
沒特別需求的話,Ctrl+/即可)

'''
a = 10
b = 5
print(a * b)
print("一起從零開始學Python,我知道10 * 5 = " + str(a * b))
# 雖然這行有「#」,但實際起作用是外層造成的
'''

如果你有一整行很長的運算或文字,
想要做換行的話,請在換行之前的行尾放上「\」
Python會將這樣延續下去的行都當成同一行解讀。
如果在直譯器的狀態下也適用,
這時候直譯器會顯示「...」,代表這行還沒輸入完。

>>> 3+5+7+\
... +11+18+\
... 23\
... +10
77

接下來就是所有程式基本上都有的方法:如果(if)
「如果...我就...」這種思維邏輯是日常中很常用到的概念,
Python中也不例外,我們常常需要很多判斷來決定下一步要怎麼走。
語法結構如下:

if 陳述式1:
    要做的事情1(可以不只一行)
elif 陳述式2:
    要做的事情2(可以不只一行)
...
else:
    要做的事情n(可以不只一行)

上面的意思是說,當陳述式1的結果是真(True)的的時候,就做「要做的事情1」
否則如果(elif, 也就是else if的意思)陳述式2是真的的時候,就做「要做的事情2」
可以一直接續,前面的陳述式(statement)一旦先碰到一組是真的時候,做完要做的事情就離開了
不會繼續往下看
一直到最後一個else的時候,前面的都不成立,就做「要做的事情n」
這個結構底下,你可以選擇使用if, if...elif...else, if...else, if...elif都可以。
(只要順序是if最先,elif其次,else擺最後即可)

其他語言在框「要做的事情」時,
通常會使用大括號{}來表達開頭和結尾,
這點在Python中有很大的不同!
Python中會在陳述式後面加上一個冒號:來做為分界,
接下來的式子執行到哪裡,並不使用大括號,而是看縮排的程式碼到哪一行
(一般縮排是用4個空格,盡量不要使用tab或2個空格)
還記得上一篇問題中的炸蝦嗎?

lee = {'核果', '油', '蝦子'}
if '醬汁' not in lee: # 李嚴並沒有做醬汁,所以這個陳述式會是真
    print('李嚴')
    print('沒醬汁')
else:
    print('有醬汁')
print('所以我說那個醬汁呢?')	# 這個print並不在else的範圍內!

我們執行上面的程式碼的結果應該會得到:

李嚴
沒醬汁
所以我說那個醬汁呢?

因為最後一行並沒有縮排,所以不會算在else的範圍內,
依舊會被print出來。
在判斷的時候,除了剛剛示範的in,
可以使用其他的比較運算子及布林運算子來計算真假。
比較運算子有:==(相等,因為一個等號是將右邊的東西指定給左邊), !=(不等於),
<(小於), >(大於), <=(小於等於), >=(大於等於), in...(前者在後者的範圍內)

布林運算子常用的有:and(且), or(或), not(否定)

>>> x=24
>>> x>3
True
>>> x<21
False
>>> 12<x<100 # 相當於12 < x and x < 100
True
>>> x == 24
True
>>> lt = [1, 3, 24, 10, 33]
>>> x in lt and not x < 23 # and/or的優先順序比較低,會等左右計算完成才處理,not會將結果反轉
True

如果有很多重的判斷的話,
我們也可以將其寫成不同層來處理,
怎麼判斷不同層的方式,一樣是看縮排來決定。

x = 24
if x % 2 == 0:
    if x % 3 == 0:
        print('6的倍數')
    else:
        print('2的倍數')
else:
    print('不是2的倍數')

執行完應該會print出'6的倍數',讀者也可以自行嘗試做出不同的多層if結構。

接著要補充一個很重要的點:
Python在處理判斷時,也可以將單純的資料型態做為判斷的依據,
這時候主要在考慮的,就是這個資料型態是否有存放東西,或者它是0
包含False, None(代表沒有東西), 0, 0.0, ''(空字串), [], (), {}, set()等,
在做為True/False的判斷中,都會被
視為False

所以例如要判斷一個list是否為空,我們可以這樣寫:

>>> lt = []
>>> if lt:
...     print('lt is not empty')
... else:
...     print('lt is empty')
...
lt is empty

接下來我們來談談迴圈
迴圈在Python裡面有兩種:while跟for。
while的語法結構如下。

while 陳述式:
    xxx
    yyy
    zzz
...

while很簡單,只要這個陳述式是真的,就會將下面的程式碼區塊執行一次
做完以後呢?回到while這行,重新判斷一次
如果還是成立,就再做一次;
一直到陳述式不成立,或者我們呼叫一些其他的東西強行跳出,才會離開。
可以用來跳離迴圈的方式名為break,顧名思義就是強行中止現在所在的迴圈
不繼續往下執行
另外有一個功能叫continue,目的是跳過這次的迴圈(只跳過這次歐!),
回到while這行,依照陳述式的結果決定要不要再繼續執行。

我們下面使用input()方法來示範,它能顯示提示字樣,
並接受使用者輸入一段字串存放,
讀者可以自行試試看,是否除非你選擇專家模式,否則完全無法離開迴圈。

while True: # 使用while True須謹慎,一定要留下可以離開的方法!
    mode = input('請問你要選擇什麼模式?1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] ')
    if mode == '3':
        print('\n選擇專家模式的難關 帶著我的夥伴 還有我的不平凡')
        break
    elif mode == '1' or mode == '2': # 簡單來說,其他模式都不給過XD
        print('不選難一點的嗎?再給你選一次!\n')
        continue # 所以在這邊會直接回到迴圈開始處,因而不會印出下一行
    print('請輸入正確的選項!\n')

print('恭喜你選擇專家模式,加油!')
C:\Users\Desolve>python fromzero.py
請問你要選擇什麼模式?1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 5545
請輸入正確的選項!

請問你要選擇什麼模式?1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 1
不選難一點的嗎?再給你選一次!

請問你要選擇什麼模式?1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 2
不選難一點的嗎?再給你選一次!

請問你要選擇什麼模式?1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 3

選擇專家模式的難關 帶著我的夥伴 還有我的不平凡
恭喜你選擇專家模式,加油!

在Python中,迴圈還有一個特別的用法,就是可以加else。

while 陳述式:
    xxx
else:
    ooo

當while正常的結束,沒有被break跳出的話,
離開後就會出來找else的區塊執行。
(讀者可將其想成if else的感覺,
正常離開迴圈就是陳述式結果為false的狀況,所以要走else路線)
反之,當迴圈是被break強行離開時,就不會走到else去了!
舉例來說,我們也可以將上面改成:

mode = ''
while mode != '3': # 使用者選專家模式才能離開!
    mode = input('請問你要選擇什麼模式?1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] ')
    if mode == '3':
        print('\n選擇專家模式的難關 帶著我的夥伴 還有我的不平凡')
    elif mode == '1' or mode == '2': # 簡單來說,其他模式都不給過XD
        print('不選難一點的嗎?再給你選一次!\n')
    else:
        print('不想玩就算了!\n') # 不想玩的,後續就不繼續給提示
        break
else: # 正常離開,表示mode輸入了'3'
    print('恭喜你選擇專家模式,加油!')
C:\Users\Desolve>python fromzero.py
請問你要選擇什麼模式?1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 1
不選難一點的嗎?再給你選一次!

請問你要選擇什麼模式?1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 2
不選難一點的嗎?再給你選一次!

請問你要選擇什麼模式?1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 3

選擇專家模式的難關 帶著我的夥伴 還有我的不平凡
恭喜你選擇專家模式,加油!

C:\Users\Desolve>python fromzero.py
請問你要選擇什麼模式?1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 8
不想玩就算了!

通常狀況下,我們會將迴圏的過程每一次的執行稱為一次迭代(iteration)
有些資料型態可以適合每次從裡面取出一個單位出來,
例如str, list, set, dict, tuple...等,
這時候我們會說這些是
可迭代的Python物件

對於可迭代的東西,我們有另一個for迴圏的模式可以輕鬆處理。
for迴圏的語法結構如下:

for xxx in ooo:
    (對xxx做事情,比如印出來)

舉例來說,我們可以從一個list中一個一個取出當中的element,並將其印出。

>>> lt = [1, -5, 3, 2, 4, 10, 100]
>>> for num in lt:
...     print(num)
...
1
-5
3
2
4
10
100
>>> index = 0 # 也可以用index的方式一個一個拿,不要忘記將index每次加1
>>> while index < len(lt):
...     print(lt[index])
...     index += 1
...
1
-5
3
2
4
10
100

如上篇文章提到的,字典的items()也會產生可迭代的物件,
我們可以按順序用name和ingre(ingredient)來對應它。

>>> shrimp = {'炸鳳尾蝦':['蝦子','核果','油'],'雲龍炸蝦':['蝦子','核果','油','豆皮','醬汁']}
>>> for name, ingre in shrimp.items():
...     print(name, ingre)
...
炸鳳尾蝦 ['蝦子', '核果', '油']
雲龍炸蝦 ['蝦子', '核果', '油', '豆皮', '醬汁']

另一方面,break, continue, else在for迴圏的用法和while迴圏的用法是一模一樣的,
讀者可以自行嘗試寫寫看。

提到了for,就不得不提另一個很常用的產生迭代的方式:range()。
range()的用法跟slice很像,都是(start, stop, step);
這當中,start不給的話會從0開始,step預設則是1,
而stop由於不像list有確定的長度,所以是必需要給出的數字。

(同樣請留意stop的位置是不算在內的,這點跟slice相同)
例如:

>>> range(7) # 只給一個數字的話是表示stop,所以相當於range(0, 7)
range(0, 7)
>>> list(range(7)) # 可以將其產生為list
[0, 1, 2, 3, 4, 5, 6]
>>> list(range(1, 5))
[1, 2, 3, 4]
>>> list(range(1, 5, -1)) # step走-1並沒有符合的數字
[]
>>> list(range(1, 5, 2))
[1, 3]
>>> list(range(10, -88, -10))
[10, 0, -10, -20, -30, -40, -50, -60, -70, -80]

因此,如果我們想要從list中從頭每次相隔2,印出其值,就可以寫成這樣:

>>> lt = [1, -5, 3, 2, 4, 10, 100]
>>> for i in range(0, len(lt), 2): # 從index 0開始,每次間隔2,直到len(lt)-1 (因為stop的位置不算)
...     print(lt[i])
...
1
3
4
100

辛苦啦!今天的內容也相當的多,
同樣請練習一下,可別偷懶呦!
那就明天見啦!


上一篇
[Day 06] 從零開始學Python - 串列(list)、Tuple(元組)、字典(dict)、集合(set):我的字典裡沒有放棄,因為我還沒有寫進去(下)
下一篇
[Day 08] 從零開始學Python - 程式結構與流程語法:如果對手太弱太簡單,那不是很爽嗎?(下)
系列文
從零開始學Python30

尚未有邦友留言

立即登入留言