狠狠撸

狠狠撸Share a Scribd company logo
笔测迟丑辞苍函式
Revised on August 24, 2021
? 內建數值函式
? 使用math套件
? 使用random套件
? 使用time套件
? 自訂函式
? 參數預設值與引數傳
遞
? 全域變數與區域變數
? lambda函式
? 函式裝飾器
? 遞迴函式與應用
? 應用實例:
? 輪流取物遊戲
? 猜數字遊戲
? 設計程式時,會發現經常用到?些特定功能的程式片段,若將這樣的
程式片段獨立出來,必要時加以參數化,使其轉化成?個單獨的程式
單元,這樣就能重複呼叫執行使用,這種程式單元稱為函式 (Function)
? 系統內建函式是內含在程式語言開發環境,可直接呼叫使用的函式庫,
例如:輸出入函式、串列函式、字串函式等
? 使用者自定函式 (簡稱自定函式) 則是程式設計者在軟體開發過程中,
因應功能需求自己定義出來的函式
內建函式與自定函式 1/3
2
內建函式與自定函式 2/3
? 內建函式就好像黑盒子,只要了解函式介面,知道給予什麼參數就可
得到所要的結果,不必瞭解函式的內部是如何設計,也無法更改函式
功能
? 自定函式是程式設計者依需求自行設計出來的,隨時可以修改維護
? 自定函式具有下列好處
? 可將較大程式軟體,依功能切割成多個程式單元,再交由多人共同設計。
如此不但可縮短程式開發的時間,也可以達到程式模組化的目的
? 將相同功能的程式片段寫成函式,只需做?次,提?程式的再利用性及可
讀性,也讓程式的除錯及維護更加容易
? 強化系統架構,主框架程式專注在系統流程管控,功能性或主題性的工作
交給函式處理,程式碼可較精簡
3
? Python語言的編譯器提供?個已定義好的函式集合稱為標準函式庫
(Standard library),包括:
? 輸出入函式
? 數值函式
? 字串函式
? 檔案輸出入函式
? 時間函式
? 亂數函式
? ...
內建函式與自定函式 3/3
4
內建數值函式 1/4
函式 說明 範例
abs(n) 取得n的絕對值 num = abs(-8) #8
round(n)
取得n四捨六入五成雙的整數值
當小數為5時,若個位數為偶數則捨去;若
個位數為奇數則進位
num = round(12.6) #13
num = round(12.4) #12
num = round(12.5) #12
num = round(11.5) #12
int(n) 將n轉換為整數(小數部份直接捨去) num = int(12.6) #12
float(n) 將n轉換為浮點數 num = float(12) #12.0
hex(n) 將n轉換為十六進位數字 num = hex(254) #0xfe
oct(n) 將n轉換為八進位數字 num = oct(254) #0376
divmod(n, m) 取得n除以m的商跟餘數 ret = divmod(23, 5) #(4, 3)
pow(n, m) 取得n的m次方 num = pow(5, 3) #125
chr(n) 取得Unicode編碼為n的字元 num = chr(0x5357) #南
ord(n) 取得字元n的Unicode編碼 num = ord('南') #21335
5
? round() 函式也可以指定要轉換的小數位數
? round(n, m)
以四捨六入五成雙方式,計算 n 到小數點第 m 位之近似值
num = round(12.34, 1) #12.3
num = round(12.36, 1) #12.4
num = round(12.35, 1) #12.3
num = round(12.35001, 1) #12.4
註:即使是浮點數也可能因為尾數換算成二進位表示法後,超過有效位數而存在截斷
誤差;12.35實際儲存值可能為12.3499999999...
內建數值函式 2/4
6
? pow()函式也可以用來計算餘數
? pow(n, m, k)
計算 n 的 m 次方,再取得除以 k 的餘數 (? % ?)
num = pow(12, 1, 5) #2
num = pow(3, 2, 5) #4
內建數值函式 3/4
7
? 學年結束,將結餘的班費 5346 元平均退還 31 位學生,則每位學生可退還
多少錢,仍剩多少錢
classFund = 5346
students = 31
print('班費剩餘 %d元, 學生有% d人' %(classFund,students))
(div, mod) = divmod(classFund, students)
print ('每人退還 %d元' %div)
print ('班費仍剩餘 %d元' %mod)
測試:
班費剩餘 5346元, 學生有 31人
每人退還 172元
班費仍剩餘 14元
內建數值函式 4/4
8
? 有些內建函式是定義在各別套件中,要使用這些內建函式時,必須先
使用import指令引用套件
? import 套件名稱
import math #匯入math套件,並可使用math套件內的任何函式
? 程式中必須以「套件名稱.函式名稱」呼叫套件內的函式
print(math.sqrt(100))
? 匯入套件時可指定別名,程式中要呼叫套件內的函式時,要在函式前
要加上別名名稱
import math as M
print(M.sqrt(100))
import指令 1/2
9
? 若覺得以「套件名稱.函式名稱」呼叫套件內的函式有些麻煩,可改用
from .. import指令
? from 套件名稱 import *
from math import * #匯入math套件,並可使用math套件所有函式
print(sqrt(100))
? 若只要匯入套件中的特定函式,如 sqrt(),其匯入時敘述為
from math import sqrt #只匯入math.sqrt函式,不可使用math套件的其它函式
print(sqrt(100))
? 匯入套件指定函式時,也可以設定函式別名
from math import sqrt as squareRoot
print(squareRoot(100)) #匯入math套件中的sqrt函式,並指定函式別名
#squareRoot(100)與sqrt(100)是?樣的效果
import指令 2/2
10
? 數值的內建函式還有定義在 math 套件中的數值函式,例如 sin()、
exp()、log() 等
? 要使用 math 套件內的函式,必須在使用前匯入 math 套件
? import math
math套件函式 1/2
函式 說明 範例
pi 圖週率常數 (3.141592653589793) num = math.pi #3.14...
e 數學常數 (2.718281828459045) num = math.e #2.71...
ceil(n) 取得大於n的最小整數 num = math.ceil(12.3) #13
floor(n) 取得小於n的最大整數 num = math.floor(12.3) #12
fabs(n) 取得浮點數n的絕對值 num = math.fabs(-12.3) #12.3
sqrt(n) 取得n的平方根 num = math.sqrt(169) #13.0
11
math套件函式 2/2
函式 說明 範例
exp(n) 取得n自然指數值(? ) num = math.exp(1) #2.71...
log(n) 取得n自然對數值(??? ?) num = math.log(math.e) #1.0
sin(n) 取得弳度為n的正弦函式值 num = math.sin(math.pi/6) #0.5
cos(n) 取得弳度為n的餘弦函式值 num = math.cos(math.pi/3) #0.5
tan(n) 取得弳度為n的正切函式值 num = math.tan(math.pi/4) #1
asin(n) 取得反正弦函式的弳度值 num = math.asin(0.5) #π/6
acos(n) 取得反餘弦函式的弳度值 num = math.acos(0.5) #π/3
atan(n) 取得反正切函式的弳度值 num = math.atan(1) #π/4
12
? 亂數函式多用於電腦、統計學、模擬、離散數學、抽樣、作業研究、
數值分析、決策等各領域,函式定義在 random 套件中
? import random
random套件函式 1/2
函式 說明 範例
randint(n1, n2) 產生一個整數 n,?1 ? ?2 random.randint(1, 10)
randrange(n1,n2,n3)
產生?個 n1 到 (n2-1) 之間每隔 n3 的
整數
random.randrange(1, 10, 2)
random() 產生一個浮點數 n,0.0 ? 1.0 random.random()
uniform(n1, n2) 產生一個浮點數 n,?1 ? ?2 random.uniform(1, 10)
choice(s) 從字串 s 中隨機取得?個字元 random.choice('python')
sample(s, n)
從字串或串列 s 中隨機取得不重複 n 個
字元,回傳串列
random.sample('python', 2)
shuffle(s) 將串列 s 隨機重新排列 random.shuffle([1,2,3,4])
13
? 隨機產生4個不重複的數字
from random import *
numStr = '0123456789'
randNum = sample(numStr, 4) #randNum為字元串列
answer = ''.join(randNum) #將字元串列合併為數字字串
print(answer)
random套件函式 2/2
14
? time 套件提供許多與時間相關函式,例如 clock()、sleep()、time() 等
? time()
取得電腦目前的時間,即自 1970-01-01 00:00:00 起到目前為止,所經過的
秒數
? Python 最小時間單位為 tick,tick 時間為 us (百萬分之?秒),因此
time()傳回值是精確到小數點 6 位的浮點數
from time import *
num = time()
print(num) #1629348277.5953765 (執行時的時間值)
time套件函式 1/5
15
? ctime()
取得電腦目前所在時區的日期、時間資料,資料型別為字串
? 傳回資料是英文字串,傳回值的格式為'星期 月份 日 時:分:秒 ?元年'
import time as T
st = T.ctime()
print(st) #Thu Aug 19 13:34:14 2021 (執行時的時間值)
time套件函式 2/5
16
? localctime()
傳回目前電腦所在時區資訊 (time.struct_time類別),包括以下資料欄
time套件函式 3/5
資料欄 說明
tm_year 時區資料的?元年份
tm_mon 時區資料的月份值(1~12)
tm_mday 時區資料的日期值(1~31)
tm_hour 時區資料的時(0~23)
tm_min 時區資料的分(0~59)
tm_sec 時區資料的秒(0~59)
tm_wday 時區資料的星期值(0~6),0表示星期?
tm_yday 時區資料的該年的第幾天(0~366)
tm_isdst 0:非日光節約時間,1:日光節約時間
17
time套件函式 4/5
from time import *
curtime = localtime()
print(type(curtime))
print(curtime)
year = curtime.tm_year
moon = curtime.tm_mon
day = curtime.tm_mday
hour = curtime.tm_hour
min = curtime.tm_min
sec = curtime.tm_sec
print('%s:%s:%s %s-%s-%s' %(hour,min,sec,year,moon,day))
測試結果:
<class 'time.struct_time'>
time.struct_time(tm_year=2021, tm_mon=8, tm_mday=19, tm_hour=15, tm_min=1,
tm_sec=38, tm_wday=3, tm_yday=231, tm_isdst=0)
15:1:38 2021-8-19
18
? sleep()
使程式暫停?段時間,單位為秒
from time import *
t1 = time()
print('暫停前電腦時間:', t1)
sleep(5)
t2 = time()
print('暫停後電腦時間:', t2)
print('程式暫停了%f秒' %(t2 - t1))
測試結果:
暫停前電腦時間: 1629357313.1758947
暫停後電腦時間: 1629357318.185649
程式暫停了5.009754秒
time套件函式 5/5
19
? 設計程式隨機產生兩題四則運算(+,-,*,/)測驗
? 第?個運算值介於 11 到 20 間整數,第二個運算值介於 1 到 10 間整數
? 除法結果四捨五入到小數點第1位
? 作答完成顯示得分及所花費時間
提示: 四捨五入到小數點第1位可採用以下程式碼
result = math.floor(value * 10 + 0.5) / 10.0
實作練習 1/3
20
from random import randint
import time
import math
total, score = 2, 0
t1 = time.time() #開始作答時間
for i in range(total):
print('第%d題' %(i + 1))
num1 = randint(11, 20) #隨機產生第?個運算值
num2 = randint(1, 10) #隨機產生第二個運算值
op = randint(1, 4) #隨機選擇四則運算
if (op == 1):
operator = '+'
result = num1 + num2
if (op == 2):
operator = '-'
result = num1 - num2
if (op == 3):
operator = '*'
result = num1 * num2
實作練習 2/3
21
if (op == 4):
operator = '/'
result = math.floor(num1 / num2 * 10 + 0.5) / 10.0
print('%d %s %d = ' %(num1, operator, num2), end = '')
ans = eval(input()) #考生輸入答案
if (ans == result):
print('答對了!')
score += 100 / total
else:
print('答錯了!')
print('正確答案 : %f' %(result))
print()
t2 = time.time() #完成作答時間
print('答題得分 : %d 分' %score)
print('花費時間 : %0.2f 秒' %(t2 - t1))
實作練習 3/3
22
? Python 使用 def 命令建立自定函式,不但可以傳送多個引數給函式,
也允許返回多個回傳值,語法如下
? def 函式名稱([參數1, 參數2...]):
程式區塊
[return 回傳值1, 回傳值2...]
? 函式名稱:命名方式比照識別字命名規則。同程式中,自定函式的名稱
不可以重複,也不可以和內建函式相同名稱
? 參數 (Parameter)
? 在函式宣告中的參數也稱為虛引數 (Formal Argument),用來接收來自呼叫
端的程式敘述所傳遞過來的資料。呼叫函式時傳入的資料稱為引數
(Argument) 或實引數 (Actual Argument)
? 若有多個參數,參數間要用逗點 (,) 隔間開。若函式不需要參數,函式名稱後
的 () 仍須保留
自訂函式 1/8
23
? 傳回值:函式執行完成後,可以傳回?個或多個結果
? 傳回值可以是資料、可以是變數、也可以是運算式,但回傳值最終會是
資料結果
? 使用 return 敘述就可以傳回結果資料,若函式的任務是沒有傳回值時,
則return敘述可省略
? 若有多個回傳值,主程式也要有多個變數來接收回傳值;如果用單?變
數接收回傳值,則全部回傳值會封裝為元組資料 (後續單元介紹)
自訂函式 2/8
24
? 有傳回值的函式呼叫
? 變數1, 變數2, ... = 函式名稱(引數1, 引數2, ...)
? 使用指定運算子「=」,將函式回傳值指定給等號左邊的變數
? 被呼叫函式的回傳值數量、資料型別,必須和呼叫敘述端的變數?致
? 自訂 ctof 函式,傳入攝氏溫度,回傳華氏溫度
def ctof(c):
f = c * 1.8 + 32
return f
tempc = float(input("請輸入攝氏溫度:"))
tempf = ctof(tempc)
print("華氏溫度為:%5.1f 度" % tempf)
測試結果:
請輸入攝氏溫度:26.5
華氏溫度為: 79.7 度
自訂函式 3/8
25
? 自訂 progression 函式,傳入等差級數首項、公差及項數,回傳級數末項
及總和
def progression(a1, d, n):
an = a1 + (n - 1) * d #末項
sn = n * (a1 + an) / 2 #和
return an, sn
a1 = eval(input('輸入數列的首項:'))
d = eval(input('輸入數列的公差:'))
n = eval(input('輸入數列的項數:'))
dd = progression(a1, d, n)
print(dd)
an, sn = progression(a1, d, n)
print('等差數列的末項為 %d,和為 %d' %(an, sn), end = '')
測試結果:
輸入數列的首項:1
輸入數列的公差:2
輸入數列的項數:6
(11, 36.0)
等差數列的末項為 11,和為 36
自訂函式 4/8
26
? 無傳回值的函式呼叫
? 函式名稱(引數1, 引數2, ...)
? 將呼叫敘述端的實引數傳給被呼叫函式端的虛引數。虛引數將所得到的
資料帶入函式內經過運算處理後,不回傳結果到原來的呼叫敘述
def printChar(ch, n):
for i in range(n):
print ('%s' %ch, end = '')
print()
ch1 = 'A'
n1 = 12
printChar(ch1, n1) #以變數作為實引數
printChar('-', 15) #以常值作為實引數
printChar('B', n1) #以常值與變數作為實引數
測試結果:
AAAAAAAAAAAA
---------------
BBBBBBBBBBBB
自訂函式 5/8
27
? 撰寫函式使用說明
? 在函式開頭使用「'''」撰寫函式的說明文件,說明文件可以跨行,直到
找到下?個「'''」
? 可用以下指令讀取函式的說明文件
? help (函式名稱)
? print (函式名稱.__doc__)
自訂函式 6/8
28
? 為 progression 函式加入說明
def progression(a1, d, n):
'''
progression(a1, d, n)函式用來計算等差級數
Args:
a1: 等差級數首項
d: 等差級數公差
n: 等差級數項數
Returns:
回等差級數未項值及總和
'''
an = a1 + (n - 1) * d #末項
sn = n * (a1 + an) / 2 #和
return an, sn
help(progression)
自訂函式 7/8
29
測試結果:
Help on function progression in module __main__:
progression(a1, d, n)
progression(a1, d, n)函式用來計算等差級數
Args:
a1: 等差級數首項
d: 等差級數公差
n: 等差級數項數
Returns:
回等差級數未項值及總和
自訂函式 8/8
30
? 設計程式計算二正整數之最大公因數與最小公倍數
? 歐幾里得演算法 (Euclidean Algorithm),也稱為輾轉相除法,用來計算兩
個整數的最大公因數(GCD,Greatest Common Divisor)
gcd ?, ?
gcd ?, ? , ? ?
?, ? 0
gcd ?, ?%? , ????
? 最小公倍數(LCM,Least Common Multiple) ??? ? ? ???
lcm(32, 12) = 32 * 12 / 4 = 96
實作練習 1/2
2 32 12 1
24 8
2 8 4
8
0
2 32 12
24
8
2 32 12 1
24 8
8 4
被除數 除數 被除數
除數 除數即為最
大公因數
被除數
31
整除
def gcd(x, y):
while ( x > 0 and y > 0 ):
if(x > y): x = x % y
else: y = y % x
return y if (x == 0) else x
while True:
a = eval(input('輸入第?個正整數a:'))
b = eval(input('輸入第二個正整數b:'))
if a > 0 and b > 0:
break
else:
print('無效輸入, 請重新輸入...')
gcd = gcd(a, b)
print('%d, %d 兩整數的GCD為 %d' %(a, b, gcd))
print('%d, %d 兩整數的LCM為 %d' %(a, b, (a * b)/gcd))
測試結果:
輸入第?個正整數a:234
輸入第二個正整數b:36
234, 36 兩整數的GCD為 18
234, 36 兩整數的LCM為 468
實作練習 2/2
32
? 設計解?元二次方程式的兩個根的函式,由使用者輸入方程式的平方
項係數 a、?次項係數 b、及常數項 c,先判斷所輸入的?元二次方程
式係數是否有實數解,再呼叫自訂函式求解
? ?元二次方程式:?? ?? ? 0
? 實數解條件:? 4?? 0
? 實數解?
實作練習 1/2
33
import math
def equation(a, b, c):
d = math.sqrt(b ** 2 – 4 * a * c)
return (-b + d)/(2 * a), (-b - d)/(2 * a)
while (1):
a = eval(input('請輸入平方項係數a:'))
b = eval(input('請輸入?次項係數b:'))
c = eval(input('請輸入常數項c:'))
if ((b ** 2 – 4 * a * c) >= 0):
break
else:
print('無解, 請重新輸入係數...')
ret = equation(a, b, c)
print('?元二次方程式的根為 %0.2f, %0.2f' %(ret[0], ret[1]))
測試結果:
請輸入平方項係數a:2
請輸入?次項係數b:3
請輸入常數項c:1
?元二次方程式的根為 -0.50, -1.00
實作練習 2/2
34
? 呼叫函式時,若引數數量與參數數量不相符,在這種情況下?般是會
產生錯誤的
? 要避免上述錯誤情形,在定義函式時,可指定參數預設值。如此?來,
若呼叫該函式時沒有傳遞引數,或傳遞的實引數數量少於參數數量時,
參數的預設值就派上用場了
? 當某?參數定義了預設值,其右側的所有參數都必須定義預設值
def greeting(name, msg = 'Good morning!', msg2 = ''):
print('Hello', name + ', ' + msg)
greet('Kate')
greet('Bruce', 'How do you do?')
測試:
Hello Kate, Good morning!
Hello Bruce, How do you do?
參數的預設值
35
? 呼叫函式時引數資料的傳遞方式有傳值呼叫 (call by value) 和參考呼
叫 (call by reference) 兩種
? 傳值呼叫
? 虛引數的資料異動時,會另外建立新的資料物件,不會影響到實引數的資
料內容
? 以下資料型別之引數採用傳值呼叫
boolean, int, float, long, str, unicode, tuple
引數的傳遞方式 1/9
36
def inc(x):
print('id of x = %d' %id(x), end = ', ')
print('x = %d' %(x))
x += 1
print('id of x = %d' %id(x), end = ', ')
print('x = %d' %(x))
a = 10
print('id of a = %d' %id(a), end = ', ')
print('a = %d' %(a))
inc(a)
print('id of a = %d' %id(a), end = ', ')
print('a = %d' %(a))
測試結果:
id of a = 140729614147616, a = 10
id of x = 140729614147616, x = 10
id of x = 140729614147648, x = 11
id of a = 140729614147616, a = 10
引數的傳遞方式 2/9
37
引數的傳遞方式 3/9
? 參考呼叫
? 實引數和虛引數共用相同資料物件,如此引數間的資料傳遞是雙向互通
? 在函式中更新虛引數的內容,則原呼叫敘述實引數的內容也跟著變動
? 以下資料型別之引數採用參考呼叫
list, dict, set
38
def additem(x):
print('id of x = %d' %id(x), end = ' ,')
print('x = ', x)
x.append(5)
print('id of x = %d' %id(x), end = ' ,')
print('x = ', x)
a = [1, 2, 3, 4]
print('id of a = %d' %id(a), end = ' ,')
print('a = ', a)
additem(a)
print('id of a = %d' %id(a), end = ' ,')
print('a = ', a)
測試結果:
id of a = 2398559902016 ,a = [1, 2, 3, 4]
id of x = 2398559902016 ,x = [1, 2, 3, 4]
id of x = 2398559902016 ,x = [1, 2, 3, 4, 5]
id of a = 2398559902016 ,a = [1, 2, 3, 4, 5]
引數的傳遞方式 4/9
39
? 在定義函式時,允許不限定傳送過來的實引數數量
? def 函式名稱(*參數):
程式區塊
[return 回傳值1, 回傳值2…]
? 呼叫函式時,不限定實引數個數,實引數間以逗號分隔
? 全部的實引數全被封裝成?個元組資料 (tuple) 傳給參數
? 元組資料的取用方式與串列資料相同
引數的傳遞方式 5/9
40
def calsum(*data):
total = 0
for x in data:
total += x
return total
print("不定數目引數範例:")
print("2個引數:calsum(4, 5) = %d" % calsum(4, 5))
print("3個引數:calsum(4, 5, 12) = %d" % calsum(4, 5, 12))
print("4個引數:calsum(4, 5, 12, 8) = %d" % calsum(4, 5, 12, 8))
測試結果:
不定數目引數範例:
2個引數:calsum(4, 5) = 9
3個引數:calsum(4, 5, 12) = 21
4個引數:calsum(4, 5, 12, 8) = 29
引數的傳遞方式 6/9
41
? 使用字典參數
? def 函式名稱(**參數):
程式區塊
[return 回傳值1, 回傳值2…]
? 呼叫函式時,不限定實引數個數,實引數間以逗號分隔
? 每個實引數使用「引數名稱 = 引數值」形式
? 全部的實引數全被封裝為成?個字典資料 (dictionary) 傳給參數
引數的傳遞方式 7/9
42
def resume(**data):
print(data)
print('字典引數範例:')
resume(name = 'Justin', age = 23, tel = '1234567')
測試結果:
字典引數範例:
{'name': 'Justin', 'age': 23, 'tel': '1234567'}
引數的傳遞方式 8/9
43
? 同時使用不定數目引數及字典參數
? def 函式名稱(*參數1, **參數2):
程式區塊
[return 回傳值1, 回傳值2…]
def resume(*index, **data):
print(index)
print(data)
for key in index:
print(data[key])
print('同時使用不定數目引數及字典引數範例:')
resume('name', 'age', 'tel', name = 'Justin', age = 23, tel = '1234567')
測試結果:
同時使用不定數目引數及字典引數範例:
('name', 'age', 'tel')
{'name': 'Justin', 'age': 23, 'tel': '1234567'}
Justin
23
1234567
引數的傳遞方式 9/9
44
? 定義在函式外的變數可供多個函式共同使用,稱為「全域變數」
(Global variable),在程式結束前會?直存在
? 在函式內建立的變數,稱為區域變數 (Local Variable)
? 區域變數僅限在所屬函式中使用,離開該函式時此類變數的記憶體會立即
被釋放掉。每次函式被呼叫時,系統會重新配置記憶體給此類變數使用
? 由於 Python 會自動建立變數,當函式內的區域變數名稱與全域變數
名稱相同,在函式內會產生「變數覆蓋」的現象
? 兩個同名稱的變數,在記憶體內是佔用不同的位址,互不影響
? 當程式流程執行到函式時,就使用這個區域所建立的區域變數,全域變數
會保留其值,等程式流程離開這個函式時,這個區域變數便會消失
? 待程式流程回到主程式時,全域變數會仍用原保留的值繼續運作
全域變數與區域變數 1/3
45
def mysub():
v2, v3 = 200, 300 #Python自動建立v2,v3區域變數
print('--in mysub--')
print('v1=%d, v2=%d, v3=%d' %(v1, v2, v3)) #v1是全域變數,v2與v3是區域變數
print('--in main program--')
v1, v2 = 10, 20
print('v1=%d, v2=%d' %(v1, v2))
mysub()
print('--in main program--')
print('v1=%d, v2=%d' %(v1, v2))
print('v1=%d, v2=%d, v3=%d' %(v1, v2, v3)) #錯誤
測試結果:
--in main program--
v1=10, v2=20
--in mysub--
v1=10, v2=200, v3=300
--in main program--
v1=10, v2=20
全域變數與區域變數 2/3
46
NameError: name 'v3' is not defined
? 若函式內須要更新全域變數內容,則函式須用 global 來宣告該全域變數
def mysub():
global v2
v2, v3 = 200, 300 #v2為全域變數,並自動建立v3區域變數
print('--in mysub--')
print('v1=%d, v2=%d, v3=%d' %(v1, v2, v3))
print('--in main program--')
v1, v2 = 10, 20
print('v1=%d, v2=%d' %(v1, v2))
mysub()
print('--in main program--')
print('v1=%d, v2=%d' %(v1, v2))
測試結果:
--in main program--
v1=10, v2=20
--in mysub--
v1=10, v2=200, v3=300
--in main program--
v1=10, v2=200
全域變數與區域變數 3/3
47
? Lambda函式是?種特別的函式
? 它是匿名函式,不需要定義名稱,且函式程式碼只能有?行指令敘述。語
法如下:
lambda 參數1, 參數2, ...:程式碼
? 下列max()函式會回傳二數中較大者
def max(m, n):
if m > n:
return m
else:
return n
可改寫如下
def max(m, n):
return m if m > n else n
lambda函式 1/5
48
? 若將max()函式轉換成lambda函式,程式如下
max = lambda m, n : m if m > n else n
print(max(10, 3))
? Lambda函式支援IIFE (immediately invoked function expression) 語
法,意思是利用 function expression 的方式來建立函式,並且立即執
行它,語法如下:
? (lambda 函式參數:指令敘述)(實引數)
print((lambda m, n:m if m > n else n)(10, 3))
lambda函式 2/5
49
? Lambda函式通常應用在以下情境
? function使用頻率偏低,不易命名,或是命名會干擾整個命名規則,採用
隨用隨扔的lambda函式,可節省記憶體
? filter()函式在可疊代的物件中,依據條件運算式,篩選特定的元素。
語法如下:
? filter(篩選函式, 可疊代的物件)
? 下列程式會篩選串列中的偶數資料
def even_fn(x):
return (x % 2 == 0)
data = [-5, 1, 3, 2, 5, -9, 20, 21]
result = list(filter(even_fn, data))
? 當需要許多不同的篩選條件時 (奇數、偶數、正數、負數…),我們就要定
義各種篩選函式
lambda函式 3/5
50
def even_fn(x):
return (x % 2 == 0)
def odd_fn(x):
return (x % 2 != 0)
def positive_fn(x):
return (x > 0)
data = [-5, 1, 3, 2, 5, -9, 20, 21]
result = list(filter(even_fn, data))
print(result)
result = list(filter(odd_fn, data))
print(result)
result = list(filter(positive_fn, data))
print(result)
測試結果:
[2, 20]
[-5, 1, 3, 5, -9, 21]
[1, 3, 2, 5, 20, 21]
lambda函式 4/5
51
? 每個篩選運算式其實都很簡單,要為不同篩選條件定義函式並命名也會有
點困擾,此時就很適合改用lambda函式
data = [-5, 1, 3, 2, 5, -9, 20, 21]
result = list(filter(lambda x: x % 2 == 0, data))
print(result)
result = list(filter(lambda x: x % 2 != 0, data))
print(result)
result = list(filter(lambda x: x > 0, data))
print(result)
測試結果:
[2, 20]
[-5, 1, 3, 5, -9, 21]
[1, 3, 2, 5, 20, 21]
lambda函式 5/5
52
? Python的函式本?就是?個物件,因此具備物件的性質
? 可以將函式設定給?個變數
def ctof(c):
return c * 1.8 + 32
fahrenheit = ctof
print(fahrenheit(25))
測試結果:
77.0
? 可以在函式裡再定義另?個函式
def fahrenheit(c):
def ctof(c):
return c * 1.8 + 32
print('華氏溫度為:%5.1f 度' % ctof(c))
fahrenheit(25)
測試結果:
華氏溫度為: 77.0 度
笔测迟丑辞苍函式的其它特性 1/4
53
? 函式可以當做參數傳給另?個函式
def jap():
print('こんにちは, ', end = '')
def eng():
print('Hello, ', end = '')
def cht():
print('你好, ', end = '')
def vietnam():
print('xin chào, ', end = '')
def sayhello(name, nationality):
nationality()
print(name)
funcs = [cht, eng, jap, vietnam]
name = input('Name: ')
i = int(input('Nationality 1-Chinese, 2-English, 3-Japanese, 4-Vietnam:'))
sayhello(name, funcs[i - 1])
測試結果:
Name: Tony
Nationality 1-Chinese, 2-English, 3-Japanese, 4-Vietnam:1
你好, Tony
笔测迟丑辞苍函式的其它特性 2/4
54
? 函式可以回傳另?個函式
def nationality(i):
def jap():
print('こんにちは, ', end = '')
def eng():
print('Hello, ', end = '')
def cht():
print('你好, ', end = '')
def vietnam():
print('xin chào, ', end = '')
funcs = [cht, eng, jap, vietnam]
return funcs[i - 1]
def sayhello(name, greeting):
greeting()
print(name)
name = input('Name: ')
i = int(input('Nationality 1-Chinese, 2-English, 3-Japanese, 4-Vietnam:'))
sayhello(name, nationality(i))
笔测迟丑辞苍函式的其它特性 3/4
55
? 內部函式可以取得包含函式的區域變數
def greeting(name, i):
def jap():
print('こんにちは! ', name)
def eng():
print('Hello! ', name)
def cht():
print('你好! ', name)
def vietnam():
print('xin chào, ', end = '')
funcs = [cht, eng, jap, vietnam]
funcs[i - 1]()
name = input('Name: ')
i = int(input('Nationality 1-Chinese, 2-English, 3-Japanese, 4-Vietnam:'))
greeting(name, i)
測試結果:
Name: Tony
Nationality 1-Chinese, 2-English, 3-Japanese, 4-Vietnam:1
你好, Tony
笔测迟丑辞苍函式的其它特性 4/4
56
? 函式裝飾器 (decorator) 功能是將?個函式的結果,再以另?個函式包
裝處理,使原函式呈現另?種功能面貌
def sayHello(name):
return 'Hello, ' + name
def htmlText(func):
def wrapper(name):
return '<p>' + func(name) + '</p>'
return wrapper
mysayHello = htmlText(sayHello)
print(mysayHello('John'))
測試結果:
<p>Hello, John</p>
? sayHello函式被當作參數傳入htmlText函式,htmlText函式以內部函式
wrapper來增加sayHello函式的功能,因此htmlText函式裝飾了sayHello
函式,所以htmlText函式就是?個裝飾器
函式裝飾器 1/3
57
? 如要將裝飾器B永遠附加在函式A,需要將執行裝飾函式敘述修改如下:
A = B(A),先前程式可修改如下
def sayHello(name):
return 'Hello, ' + name
def htmlText(func):
def wrapper(name):
return '<p>' + func(name) + '</p>'
return wrapper
mysayHello = htmlText(sayHello)
print(mysayHello('John'))
測試結果:
<p>Hello, John</p>
函式裝飾器 2/3
58
? Python 提供更簡潔的裝飾器語法,在被裝飾的函式前,加上@符號及
裝飾器名稱,就不需要執行附加裝飾器 A = B(A) 的指令
? @裝飾器
def 被裝飾函式():
def htmlText(func):
def wrapper(name):
return '<p>' + func(name) + '</p>'
return wrapper
@htmlText
def sayHello(name):
return 'Hello, ' + name
print(sayHello('John'))
測試結果:
<p>Hello, John</p>
函式裝飾器 3/3
59
? 函式間可以相互呼叫,除了呼叫別的函式外,也可呼叫自己本?,這
種函式呼叫自己的方式稱為「遞迴」
? 遞迴是?種應用極廣的程式設計技術,在函式執行的過程不斷地的呼
叫函式自?,但每?次呼叫,會完成整體之部份作業,直到遇到終止
再呼叫函式自?的條件時,才會停止遞迴逐層返回
? 如果?個問題能拆成同形式且較小範圍時,就非常適合使用遞迴函式
來設計
? 例如要計算1 + 2 … + 10的總和時,可以拆成1和2 + 3 … +10;2 + 3 … + 10
又可以拆成2和3 + 4 … + 10,其餘類推,此時就可以設計成遞迴函式
? 數列、階乘、費氏級數、輾轉相除法、排列、組合、堆疊、河內塔、八個
皇后、樹的走訪、老鼠走迷宮…等問題都具備這種特性
? 如果遞迴的函式內沒有設定終止呼叫的條件,則這樣的函式會形成無
窮遞迴,造成程式無法正常結束
何謂遞迴
60
? 計算 sum = 1 + 2 + 3 + ... + (n-1) + n 數列總和
? sum(n) = 1 for n == 1
? sum(n) = n + sum(n-1) for n > 1
def f(n):
if n == 1:
return 1
else : #n > 0
return n + f(n - 1)
n = eval(input('n = '))
sum = f(n)
print('1 + 2 + ... + %d = %d' %(n, sum))
測試結果:
n = 5
1 + 2 + ... + 5 = 15
遞迴應用實例 1/12
遞迴公式
61
? sum(5)執行流程
遞迴應用實例 2/12
sum(5)
5 + sum(4)
4 + sum(3)
3 + sum(2)
2 + sum(1)
1
1
3
6
10
15
62
? 計算 sum = 1 – 4 + 7 – 10 + ... – (n-3) + n 數列總和
? sum(n) = 1 for n == 1
? sum(n) = (1 + 3(n-1)) + sum(n-1) for n == 奇數
? sum(n) = -(1 + 3(n-1)) + sum(n-1) for n == 偶數
def g(n):
if (n == 1):
return 1
elif (n % 2 == 0): #n > 0,為偶數
return -(1 + 3 * (n - 1)) + g(n - 1)
else: #n > 0,為奇數
return 1 + 3 * (n - 1) + g(n - 1)
n = eval(input('n = '))
sum = g(n)
if (n % 2 == 1): #n輸入值為奇數
print('1 – 4 + 7 – ... + %d = %d' %(1 + 3 * (n - 1), sum))
else: #n輸入值為偶數
print('1 – 4 + 7 – ... - %d = %d' %(1 + 3 * (n - 1), sum))
遞迴應用實例 3/12
63
? 計算 n! = n * (n-1) * (n-2) * ... * 1 乘積
? n! = 1 for n <= 1
? n! = n + (n-1)! for n > 1
def factorial(n):
if n <= 1:
return 1
else : #n > 1
return n * factorial(n - 1)
while True:
n = eval(input('n = '))
if (n >= 1):
break
else:
print('輸入資料不符, 請重新輸入...')
print('%d! = %d' %(n, factorial(n)))
測試結果:
n = 4
4! = 24
遞迴應用實例 4/12
64
? 輾轉相除法就是將兩數相除,能整除則除數為最大公因數;不能整除,
則除數變為被除數,餘數變為除數,再將兩數相除,以此類推
def GCD(p, q):
if (p % q == 0):
return q
else :
return GCD(q, p % q)
x = eval(input('x = '))
y = eval(input('y = '))
if (x < y):
x, y = y, x
gcd = GCD(x, y)
print('GCD(%d, %d) = %d' %(x, y, gcd))
測試結果:
x = 234
y = 48
GCD(234, 48) = 6
遞迴應用實例 5/12
gcd p, ?
? ?%? 0
gcd ?, ?%? ?%? 0
65
? ?元1200年代的歐洲數學家Fibonacci提出假說:
? 若有?對免子每個月生?對小免子,兩個月後小免子也開始生產。前兩個
月都只有?對免子,第三個月就有兩對免子,第四個月有三對免子,第五
個月有五對免子…
? 假設免子都沒有死亡,則每個月免子的總對數就形成了?種數列,即為
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
? 這種數列被稱為「費氏數列」
遞迴應用實例 6/12
?
0 ? 0
1 ? 1
? ? ? 2
66
def fib(n):
if (n == 0):
return 0
elif (n == 1):
return 1
else: #n >= 2
return fib(n - 1) + fib(n - 2)
n = eval(input('n = '))
print('費氏數列第 %d 項為 %d' %(n, fib(n)))
測試結果:
n = 10
費氏數列第 10 項為 55
遞迴應用實例 7/12
67
? 有n個不同的物品,要挑出 k 個的方法數有幾個?這是數學上「組合」
的題目,我們用 C(n, k) 來表示。若有針對某個特定物品,會分成兩種
互斥情況:
1. 選到這個特定物品,就再從剩下的n-1個物品中挑出k-1個物品,則會有
C(n-1, k-1)個方法數
2. 沒有選到這個特定物品,就再從剩下的n-1個物品中挑出k個物品,則會有
C(n-1, k)個方法數
? 所以,當 n = k 或 k = 0 時,則 C(n, k) = 1;
當 n > k 時,則
C(n, k) = C(n-1, k-1) + C(n-1, k)
遞迴應用實例 8/12
68
def C(n, k):
if n == k or k == 0:
return 1
else :
return C(n - 1, k - 1) + C(n - 1, k)
while True:
n = eval(input('n = '))
k = eval(input('k = '))
if n >= 0 and k >= 0 and n > k:
break
else:
print('輸入資料不符, 請重新輸入...')
ans = C(n, k)
print('組合 C(%d, %d) = %d' %(n, k, ans))
測試結果:
n = 5
k = 2
組合 C(5, 2) = 10
遞迴應用實例 9/12
69
? 河內塔問題
有三根杆子A,B,C。A杆上有 N 個 (N>1) 穿孔圓盤,盤的尺寸由下到上依
次變小。要求按下列規則將所有圓盤移至 C 杆:
? 每次只能移動?個圓盤
? 大盤不能疊在小盤上面
? 提示:可將圓盤臨時置於 B 杆,也可將從 A 杆移出的圓盤重新移回 A 杆,
但都必須遵循上述兩條規則
遞迴應用實例 10/12
70
A B C
A B C
? 將?個 N 層河內塔由 A 桿移到 C 桿。依照上面的解法
? 先將前 N-1 層的圓盤先移到 B 桿
? 再將第 N 層的圓盤移到 C 桿
? 將 B 桿上的圓盤全部移到 C 桿
遞迴應用實例 11/12
71
def Hanoi(n, a, b, c):
if n == 1:
print('move %d %s --> %s' %(n, a, c))
return
Hanoi(n - 1, a, c, b)
print('move %d %s --> %s' %(n, a, c))
Hanoi(n - 1, b, a, c)
n = int(input('Number of rings on A: '))
Hanoi(n, 'A', 'B', 'C')
測試結果:
Number of rings on A: 3
move 1 A --> C
move 2 A --> B
move 1 C --> B
move 3 A --> C
move 1 B --> A
move 2 B --> C
move 1 A --> C
遞迴應用實例 12/12
72
? 在執行遞迴的過程中,系統必須使用堆疊記錄每?層的中間值,然後
去下?層繼續進行計算,直到終止條件被滿?。然而,萬?計算量太
大、或設計不良使得終止條件?直沒有被滿?,就會造成系統資源被
recursion 耗盡
? 為了避免這件事情的發生,Python 對於遞迴次數 (深度) 有所限制,
也就是說,它透過限制呼叫遞迴函式的次數,來杜絕你的遞迴無止盡
地跑下去這個可能性。透過 sys 模組中的 getrecursionlimit() 函式,
可取得遞迴函式的次數限制, setrecursionlimit()函式可重設遞迴函式
的次數限制
import sys
sys.getrecursionlimit()
測試結果:
3000
遞迴限制
73
? 遊戲規則
? 桌面有?堆?子
? 遊戲?開始隨機決定該回遊戲之?子總數 (18~23之間)
? 玩家與電腦輪流拿取?子,每回至少要拿?顆,最多可拿N顆
? 遊戲?開始隨機決定該回遊戲之每回合拿取?子上限值 (3~5)
? 拿到最後?顆?子者落敗
? 隨機決定誰先拿取?子
應用實例:輪流取物遊戲 1/7
74
? 拿取策略分析
? 以最多拿3個為例
? max_take = 3之決策樹
? max_take + 1為?個完整回合可控制的拿取總數
應用實例:輪流取物遊戲 2/7
玩家 1 2 3
電腦 1~3 1~3 1~3
合計拿取數 2, 3, 4 3, 4, 5 4, 5, 6
75
n-1
n
n-2 n-3
n-4
n-3
n-2 n-5 n-6
1 2 3
1 2 3 1 2 3 1 2 3
對手可能拿取數量
自已可以拿取數量
? 1 + (max_take+1) * N組成的節點為關鍵路徑節點
? take = (total-1) % (max_take + 1)
? 如果計算結果為 0 表示對手佔據關鍵節點,則隨機取 1~max_take
? max_take = 3之決策樹
? 先佔據關鍵節點者,就能掌控遊戲
應用實例:輪流取物遊戲 3/7
76
1
3 4
5
11
7
9
6 8
3 2 1
1 2 3
10 12
1 2 3
2
3 2 1
1 2 3
對手可能拿取數量
對手可能拿取數量
? 亂數決定?子總數
import random
total = random.randint(18, 23) #隨機產生18~23的?子數
? 亂數決定每回合可拿取的?子上限
max_take = random.randint(3, 5) #隨機產生3~5間的拿取上限值
? 顯示遊戲訊息
print('共有%d個?子,每回只能拿取1~%d個,拿到最後?個?子者落敗' %(total, max_take))
? 回合制處理作業
turn = random.randint(0, 9) % 2 #隨機決定誰先,0電腦, 1玩家
if (turn == 1): print('玩家先')
else: print('電腦先')
應用實例:輪流取物遊戲 4/7
77
? 玩家回合作業
def player_turn():
global total
run = True
while (run):
try:
take = int(input('要取走幾個?子頭(1~%d):' %max_take))
if (take >= 1 and take <= max_take):
run = False
total = total - take
print('玩家取走%d個?子,剩下%d個' %(take, total))
else:
print('只能取走1~%d個?子' %max_take)
except:
print('必須輸入數值')
應用實例:輪流取物遊戲 5/7
78
? 電腦回合作業
def computer_turn():
global total
take = (total - 1) % (max_take + 1)
if (take == 0):
take = random.randint(1, max_take)
total = total - take;
print('電腦取走%d個?子,剩下%d個' %(take, total))
應用實例:輪流取物遊戲 6/7
79
? 主程式
while(True):
if (turn):
player_turn()
turn = 1 - turn #換手
if (total == 1):
print('玩家獲勝')
break
else:
computer_turn()
turn = 1 - turn #換手
if (total == 1):
print('電腦獲勝')
break
應用實例:輪流取物遊戲 7/7
80
? 遊戲規則
? 電腦與玩家各自設定?組4位數不重複的數值為謎底
? 玩家與電腦輸流猜對手數值,對家必須依據自已的答案提供正確提示
? 玩家先猜
? A代表數字正確位置也正確,B代表數字正確但位置錯誤
? 例如正確答案為 5234,而對手猜 5346時,其中 5 的位置對了,記為1A;
3 和 4 這兩個數字對了,而位置不對,記為2B;因此要提示1A2B
? 先猜中對手答案者獲勝
應用實例:猜數字遊戲 1/11
81
5 2 3 4
5 3 4 6
結果為1A2B
答案值
猜測值
? 電腦猜數字策略
1. 前二次固定猜 1357 及 8642 收集答案提示
2. 之後由 9876 開始遞減,搜尋符合下列條件的可能答案
1) 4 個位數之數字不重複
2) 與之前記錄中的猜測值比對,必須得到與記錄中相同的答案題示
3. 如果答錯則增加?組猜測值與答案提示記錄,回到步驟 2
應用實例:猜數字遊戲 2/11
82
from random import sample
count = 0 #局數
randNum = sample('0123456789', 4) #隨機取出4個數字
answer = ''.join(randNum) #轉換為數字字串
guess = 9876 #電腦猜測值
playerNums = [] #用來記錄玩家每?回合的猜測值
playerHints = [] #用來記錄玩家每?回合的猜測結果
computerNums = [] #用來記錄電腦每?回合的猜測值
computerHints = [] #用來記錄電腦每?回合的猜測結果
應用實例:猜數字遊戲 3/11
83
#顯示所有回合猜測值及結果
def show_detail(guesslist, resultlist):
for i in range(len(guesslist)) :
print ('(%d) %s/%s' % (i + 1, guesslist[i], resultlist[i]))
#比對guess與answer數值字串內容,回傳?A?B之a, b值
def check(guess, answer):
a = b = 0
for i in range(4):
if guess[i] in answer:
if i == answer.find(guess[i]) :
a += 1
else:
b += 1
return a, b
應用實例:猜數字遊戲 4/11
84
#找下?組數值不重複的4位數數值字串
def next_guess():
global guess
if (guess < 123):
print('提示有誤,請重新檢查')
sys.exit()
while (True):
temp = guess
tempguess = ['0', '0', '0', '0']
for i in range(3, -1, -1):
tempguess[i] = chr(temp % 10 + 48)
temp //= 10
computer_guess = ''.join(tempguess)
for ch in computer_guess: #檢查數字字串是否有重複的數字
if (computer_guess.count(ch) > 1):
guess -= 1 #換下?個數字
break;
else:
return computer_guess #回傳猜測值
應用實例:猜數字遊戲 5/11
85
#驗證猜測值的合理性,假設猜測值為正確答案,那麼與先前所有猜測值應得到同樣的比對結果
def is_reasonable(numstr):
for c in range(len(computerNums)):
a, b = check(numstr, computerNums[c])
if ((chr(a + 48) != computerHints[c][0]) or
(chr(b + 48) != computerHints[c][2])):
return False #與先前比對結果不吻合
return True
應用實例:猜數字遊戲 6/11
86
#玩家回合處理作業
def player_turn():
wellform = False
while (wellform == False):
user_guess = input('輸入四個不重複數字:')
if (user_guess.isdigit() == False) :
print ('***錯誤:只能輸入數字,請重新輸入')
continue
if (len(user_guess) != 4) :
print ('***錯誤:必須輸入四個數字,請重新輸入')
continue
for ch in user_guess: #檢查是否有重複的數字
if (user_guess.count(ch) > 1):
print ('***錯誤:數字不可重複,請重新輸入')
break
else:
wellform = True
應用實例:猜數字遊戲 7/11
87
a, b = check(user_guess, answer) #檢查猜測結果
result = '%dA%dB' %(a, b)
print(result)
playerNums.append(user_guess) #記錄猜測值
playerHints.append(result) #記錄答案提示
return (a == 4)
應用實例:猜數字遊戲 8/11
88
#電腦回合處理作業
def computer_turn():
global guess
if (count == 0):
computer_guess = '1357'
elif (count == 1):
computer_guess = '8642'
else:
validate = False
while (validate == False):
computer_guess = next_guess()
if (is_reasonable(computer_guess)):
validate = True
else:
guess -= 1 #換下?組數值
print('電腦猜%s' %computer_guess)
應用實例:猜數字遊戲 9/11
89
a = int(input('有幾個數字及位置都正確?'))
b = int(input('有幾個數字正確,但位置不正確?'))
result = '%dA%dB' %(a, b)
print(result)
if (a == 4):
return True
else:
computerHints.append(result) #記錄猜測提示
computerNums.append(computer_guess) #記錄猜測結果
guess -= 1
return False
應用實例:猜數字遊戲 10/11
90
#主程式
while (True):
print ('-' * 20)
print('player's turn')
show_detail(playerNums, playerHints)
if (player_turn()):
print ('Congratulations! Your are winner !!')
break;
print ('-' * 20)
print('computer's turn')
show_detail(computerNums, computerHints)
if (computer_turn()):
print ('Computer wins this game !!')
break;
count += 1
應用實例:猜數字遊戲 11/11
91
? 程式中若要使用math套件的sqrt函式,又要使用squareRoot別名,則
下列匯入敘述何者正確?
A. from math.sqrt as squareRoot
B. from math import sqrt as squareRoot
C. import math.sqrt as squareRoot
D. import sqrt from math as squareRoot
自我評量 1/9
92
? 在程式中要從10~20之間隨機產生?整數,下列何者正確?
A. random.randint(10, 20)
B. random.randrange(10, 20, 1)
C. random.randint(10, 21)
D. random.randrange(11, 21, 1)
自我評量 2/9
93
? 在程式中要從0.0~1.0之間隨機產生?浮點數,下列何者正確?
A. random.randint(0, 1)
B. random.randrange(0.0, 1.0)
C. random.random(0, 1)
D. random.random()
自我評量 3/9
94
? 要隨機產生?個整數,但這個整數必須符合下列條件
? 數字是3的倍數
? 最小數是9
? 最大數是99
A. import random as R
print(R.randint(3, 33) * 3)
B. from random import *
print(randint(3, 32) * 3)
C. from random import randrange
print(randrange(3, 99, 3))
D. from random import randrange as rnd
print(rnd(3, 99, 3))
自我評量 4/9
95
自我評量 5/9
? 設計?函式,傳入引數n為浮點數,回傳值為正整數值,則函式會使用
到下列那些敘述?
A. math.abs(n)
B. math.fabs(n)
C. math.round(n)
D. math.float(n)
E. math.floor(n)
F. math.ceil(n)
G. math.fmod(n)
H. math.int(n)
96
? 串列 A = [1,3,9,2,5,8,4,9,6,7],呼叫 f(A, 10) 後,回傳值為何?
def f(A, n):
index = 0
for i in range(n):
if A[i] >= A[index]:
index = i
return index
1. 1
2. 2
3. 7
4. 9
自我評量 6/9
97
? 給定 g(x) 函式如下,則 g(13) 傳回值為何?
def g(x):
if (x > 1):
return g(x - 2) + 3
return x
1. 16
2. 18
3. 19
4. 22
自我評量 7/9
98
自我評量 8/9
? 下列程式碼是?個計算n階層的函式,請問要如何修改才能到正確旳結
果?
1. def f(n):
2. fac = 1
3. if (n >= 0):
4. fac = n * f(n - 1)
5. return fac
1. 第2行改為fac = n
2. 第4行改為fac = n * f(n + 1)
3. 第3行改為if (n > 0):
4. 第4行改為fac = fac * f(n - 1)
99
自我評量 9/9
? 給定下列g()函式及k()函式,執行g(3)後的傳回值為何?
def k(a, n):
if (n >= 0):
return (k(a, n - 1) + a[n])
else:
return 0
def g(n):
a = [5, 4, 3, 2, 1]
return k(a, n)
1. 5
2. 12
3. 14
4. 15
100

More Related Content

笔测迟丑辞苍函式

  • 1. 笔测迟丑辞苍函式 Revised on August 24, 2021 ? 內建數值函式 ? 使用math套件 ? 使用random套件 ? 使用time套件 ? 自訂函式 ? 參數預設值與引數傳 遞 ? 全域變數與區域變數 ? lambda函式 ? 函式裝飾器 ? 遞迴函式與應用 ? 應用實例: ? 輪流取物遊戲 ? 猜數字遊戲
  • 2. ? 設計程式時,會發現經常用到?些特定功能的程式片段,若將這樣的 程式片段獨立出來,必要時加以參數化,使其轉化成?個單獨的程式 單元,這樣就能重複呼叫執行使用,這種程式單元稱為函式 (Function) ? 系統內建函式是內含在程式語言開發環境,可直接呼叫使用的函式庫, 例如:輸出入函式、串列函式、字串函式等 ? 使用者自定函式 (簡稱自定函式) 則是程式設計者在軟體開發過程中, 因應功能需求自己定義出來的函式 內建函式與自定函式 1/3 2
  • 3. 內建函式與自定函式 2/3 ? 內建函式就好像黑盒子,只要了解函式介面,知道給予什麼參數就可 得到所要的結果,不必瞭解函式的內部是如何設計,也無法更改函式 功能 ? 自定函式是程式設計者依需求自行設計出來的,隨時可以修改維護 ? 自定函式具有下列好處 ? 可將較大程式軟體,依功能切割成多個程式單元,再交由多人共同設計。 如此不但可縮短程式開發的時間,也可以達到程式模組化的目的 ? 將相同功能的程式片段寫成函式,只需做?次,提?程式的再利用性及可 讀性,也讓程式的除錯及維護更加容易 ? 強化系統架構,主框架程式專注在系統流程管控,功能性或主題性的工作 交給函式處理,程式碼可較精簡 3
  • 4. ? Python語言的編譯器提供?個已定義好的函式集合稱為標準函式庫 (Standard library),包括: ? 輸出入函式 ? 數值函式 ? 字串函式 ? 檔案輸出入函式 ? 時間函式 ? 亂數函式 ? ... 內建函式與自定函式 3/3 4
  • 5. 內建數值函式 1/4 函式 說明 範例 abs(n) 取得n的絕對值 num = abs(-8) #8 round(n) 取得n四捨六入五成雙的整數值 當小數為5時,若個位數為偶數則捨去;若 個位數為奇數則進位 num = round(12.6) #13 num = round(12.4) #12 num = round(12.5) #12 num = round(11.5) #12 int(n) 將n轉換為整數(小數部份直接捨去) num = int(12.6) #12 float(n) 將n轉換為浮點數 num = float(12) #12.0 hex(n) 將n轉換為十六進位數字 num = hex(254) #0xfe oct(n) 將n轉換為八進位數字 num = oct(254) #0376 divmod(n, m) 取得n除以m的商跟餘數 ret = divmod(23, 5) #(4, 3) pow(n, m) 取得n的m次方 num = pow(5, 3) #125 chr(n) 取得Unicode編碼為n的字元 num = chr(0x5357) #南 ord(n) 取得字元n的Unicode編碼 num = ord('南') #21335 5
  • 6. ? round() 函式也可以指定要轉換的小數位數 ? round(n, m) 以四捨六入五成雙方式,計算 n 到小數點第 m 位之近似值 num = round(12.34, 1) #12.3 num = round(12.36, 1) #12.4 num = round(12.35, 1) #12.3 num = round(12.35001, 1) #12.4 註:即使是浮點數也可能因為尾數換算成二進位表示法後,超過有效位數而存在截斷 誤差;12.35實際儲存值可能為12.3499999999... 內建數值函式 2/4 6
  • 7. ? pow()函式也可以用來計算餘數 ? pow(n, m, k) 計算 n 的 m 次方,再取得除以 k 的餘數 (? % ?) num = pow(12, 1, 5) #2 num = pow(3, 2, 5) #4 內建數值函式 3/4 7
  • 8. ? 學年結束,將結餘的班費 5346 元平均退還 31 位學生,則每位學生可退還 多少錢,仍剩多少錢 classFund = 5346 students = 31 print('班費剩餘 %d元, 學生有% d人' %(classFund,students)) (div, mod) = divmod(classFund, students) print ('每人退還 %d元' %div) print ('班費仍剩餘 %d元' %mod) 測試: 班費剩餘 5346元, 學生有 31人 每人退還 172元 班費仍剩餘 14元 內建數值函式 4/4 8
  • 9. ? 有些內建函式是定義在各別套件中,要使用這些內建函式時,必須先 使用import指令引用套件 ? import 套件名稱 import math #匯入math套件,並可使用math套件內的任何函式 ? 程式中必須以「套件名稱.函式名稱」呼叫套件內的函式 print(math.sqrt(100)) ? 匯入套件時可指定別名,程式中要呼叫套件內的函式時,要在函式前 要加上別名名稱 import math as M print(M.sqrt(100)) import指令 1/2 9
  • 10. ? 若覺得以「套件名稱.函式名稱」呼叫套件內的函式有些麻煩,可改用 from .. import指令 ? from 套件名稱 import * from math import * #匯入math套件,並可使用math套件所有函式 print(sqrt(100)) ? 若只要匯入套件中的特定函式,如 sqrt(),其匯入時敘述為 from math import sqrt #只匯入math.sqrt函式,不可使用math套件的其它函式 print(sqrt(100)) ? 匯入套件指定函式時,也可以設定函式別名 from math import sqrt as squareRoot print(squareRoot(100)) #匯入math套件中的sqrt函式,並指定函式別名 #squareRoot(100)與sqrt(100)是?樣的效果 import指令 2/2 10
  • 11. ? 數值的內建函式還有定義在 math 套件中的數值函式,例如 sin()、 exp()、log() 等 ? 要使用 math 套件內的函式,必須在使用前匯入 math 套件 ? import math math套件函式 1/2 函式 說明 範例 pi 圖週率常數 (3.141592653589793) num = math.pi #3.14... e 數學常數 (2.718281828459045) num = math.e #2.71... ceil(n) 取得大於n的最小整數 num = math.ceil(12.3) #13 floor(n) 取得小於n的最大整數 num = math.floor(12.3) #12 fabs(n) 取得浮點數n的絕對值 num = math.fabs(-12.3) #12.3 sqrt(n) 取得n的平方根 num = math.sqrt(169) #13.0 11
  • 12. math套件函式 2/2 函式 說明 範例 exp(n) 取得n自然指數值(? ) num = math.exp(1) #2.71... log(n) 取得n自然對數值(??? ?) num = math.log(math.e) #1.0 sin(n) 取得弳度為n的正弦函式值 num = math.sin(math.pi/6) #0.5 cos(n) 取得弳度為n的餘弦函式值 num = math.cos(math.pi/3) #0.5 tan(n) 取得弳度為n的正切函式值 num = math.tan(math.pi/4) #1 asin(n) 取得反正弦函式的弳度值 num = math.asin(0.5) #π/6 acos(n) 取得反餘弦函式的弳度值 num = math.acos(0.5) #π/3 atan(n) 取得反正切函式的弳度值 num = math.atan(1) #π/4 12
  • 13. ? 亂數函式多用於電腦、統計學、模擬、離散數學、抽樣、作業研究、 數值分析、決策等各領域,函式定義在 random 套件中 ? import random random套件函式 1/2 函式 說明 範例 randint(n1, n2) 產生一個整數 n,?1 ? ?2 random.randint(1, 10) randrange(n1,n2,n3) 產生?個 n1 到 (n2-1) 之間每隔 n3 的 整數 random.randrange(1, 10, 2) random() 產生一個浮點數 n,0.0 ? 1.0 random.random() uniform(n1, n2) 產生一個浮點數 n,?1 ? ?2 random.uniform(1, 10) choice(s) 從字串 s 中隨機取得?個字元 random.choice('python') sample(s, n) 從字串或串列 s 中隨機取得不重複 n 個 字元,回傳串列 random.sample('python', 2) shuffle(s) 將串列 s 隨機重新排列 random.shuffle([1,2,3,4]) 13
  • 14. ? 隨機產生4個不重複的數字 from random import * numStr = '0123456789' randNum = sample(numStr, 4) #randNum為字元串列 answer = ''.join(randNum) #將字元串列合併為數字字串 print(answer) random套件函式 2/2 14
  • 15. ? time 套件提供許多與時間相關函式,例如 clock()、sleep()、time() 等 ? time() 取得電腦目前的時間,即自 1970-01-01 00:00:00 起到目前為止,所經過的 秒數 ? Python 最小時間單位為 tick,tick 時間為 us (百萬分之?秒),因此 time()傳回值是精確到小數點 6 位的浮點數 from time import * num = time() print(num) #1629348277.5953765 (執行時的時間值) time套件函式 1/5 15
  • 16. ? ctime() 取得電腦目前所在時區的日期、時間資料,資料型別為字串 ? 傳回資料是英文字串,傳回值的格式為'星期 月份 日 時:分:秒 ?元年' import time as T st = T.ctime() print(st) #Thu Aug 19 13:34:14 2021 (執行時的時間值) time套件函式 2/5 16
  • 17. ? localctime() 傳回目前電腦所在時區資訊 (time.struct_time類別),包括以下資料欄 time套件函式 3/5 資料欄 說明 tm_year 時區資料的?元年份 tm_mon 時區資料的月份值(1~12) tm_mday 時區資料的日期值(1~31) tm_hour 時區資料的時(0~23) tm_min 時區資料的分(0~59) tm_sec 時區資料的秒(0~59) tm_wday 時區資料的星期值(0~6),0表示星期? tm_yday 時區資料的該年的第幾天(0~366) tm_isdst 0:非日光節約時間,1:日光節約時間 17
  • 18. time套件函式 4/5 from time import * curtime = localtime() print(type(curtime)) print(curtime) year = curtime.tm_year moon = curtime.tm_mon day = curtime.tm_mday hour = curtime.tm_hour min = curtime.tm_min sec = curtime.tm_sec print('%s:%s:%s %s-%s-%s' %(hour,min,sec,year,moon,day)) 測試結果: <class 'time.struct_time'> time.struct_time(tm_year=2021, tm_mon=8, tm_mday=19, tm_hour=15, tm_min=1, tm_sec=38, tm_wday=3, tm_yday=231, tm_isdst=0) 15:1:38 2021-8-19 18
  • 19. ? sleep() 使程式暫停?段時間,單位為秒 from time import * t1 = time() print('暫停前電腦時間:', t1) sleep(5) t2 = time() print('暫停後電腦時間:', t2) print('程式暫停了%f秒' %(t2 - t1)) 測試結果: 暫停前電腦時間: 1629357313.1758947 暫停後電腦時間: 1629357318.185649 程式暫停了5.009754秒 time套件函式 5/5 19
  • 20. ? 設計程式隨機產生兩題四則運算(+,-,*,/)測驗 ? 第?個運算值介於 11 到 20 間整數,第二個運算值介於 1 到 10 間整數 ? 除法結果四捨五入到小數點第1位 ? 作答完成顯示得分及所花費時間 提示: 四捨五入到小數點第1位可採用以下程式碼 result = math.floor(value * 10 + 0.5) / 10.0 實作練習 1/3 20
  • 21. from random import randint import time import math total, score = 2, 0 t1 = time.time() #開始作答時間 for i in range(total): print('第%d題' %(i + 1)) num1 = randint(11, 20) #隨機產生第?個運算值 num2 = randint(1, 10) #隨機產生第二個運算值 op = randint(1, 4) #隨機選擇四則運算 if (op == 1): operator = '+' result = num1 + num2 if (op == 2): operator = '-' result = num1 - num2 if (op == 3): operator = '*' result = num1 * num2 實作練習 2/3 21
  • 22. if (op == 4): operator = '/' result = math.floor(num1 / num2 * 10 + 0.5) / 10.0 print('%d %s %d = ' %(num1, operator, num2), end = '') ans = eval(input()) #考生輸入答案 if (ans == result): print('答對了!') score += 100 / total else: print('答錯了!') print('正確答案 : %f' %(result)) print() t2 = time.time() #完成作答時間 print('答題得分 : %d 分' %score) print('花費時間 : %0.2f 秒' %(t2 - t1)) 實作練習 3/3 22
  • 23. ? Python 使用 def 命令建立自定函式,不但可以傳送多個引數給函式, 也允許返回多個回傳值,語法如下 ? def 函式名稱([參數1, 參數2...]): 程式區塊 [return 回傳值1, 回傳值2...] ? 函式名稱:命名方式比照識別字命名規則。同程式中,自定函式的名稱 不可以重複,也不可以和內建函式相同名稱 ? 參數 (Parameter) ? 在函式宣告中的參數也稱為虛引數 (Formal Argument),用來接收來自呼叫 端的程式敘述所傳遞過來的資料。呼叫函式時傳入的資料稱為引數 (Argument) 或實引數 (Actual Argument) ? 若有多個參數,參數間要用逗點 (,) 隔間開。若函式不需要參數,函式名稱後 的 () 仍須保留 自訂函式 1/8 23
  • 24. ? 傳回值:函式執行完成後,可以傳回?個或多個結果 ? 傳回值可以是資料、可以是變數、也可以是運算式,但回傳值最終會是 資料結果 ? 使用 return 敘述就可以傳回結果資料,若函式的任務是沒有傳回值時, 則return敘述可省略 ? 若有多個回傳值,主程式也要有多個變數來接收回傳值;如果用單?變 數接收回傳值,則全部回傳值會封裝為元組資料 (後續單元介紹) 自訂函式 2/8 24
  • 25. ? 有傳回值的函式呼叫 ? 變數1, 變數2, ... = 函式名稱(引數1, 引數2, ...) ? 使用指定運算子「=」,將函式回傳值指定給等號左邊的變數 ? 被呼叫函式的回傳值數量、資料型別,必須和呼叫敘述端的變數?致 ? 自訂 ctof 函式,傳入攝氏溫度,回傳華氏溫度 def ctof(c): f = c * 1.8 + 32 return f tempc = float(input("請輸入攝氏溫度:")) tempf = ctof(tempc) print("華氏溫度為:%5.1f 度" % tempf) 測試結果: 請輸入攝氏溫度:26.5 華氏溫度為: 79.7 度 自訂函式 3/8 25
  • 26. ? 自訂 progression 函式,傳入等差級數首項、公差及項數,回傳級數末項 及總和 def progression(a1, d, n): an = a1 + (n - 1) * d #末項 sn = n * (a1 + an) / 2 #和 return an, sn a1 = eval(input('輸入數列的首項:')) d = eval(input('輸入數列的公差:')) n = eval(input('輸入數列的項數:')) dd = progression(a1, d, n) print(dd) an, sn = progression(a1, d, n) print('等差數列的末項為 %d,和為 %d' %(an, sn), end = '') 測試結果: 輸入數列的首項:1 輸入數列的公差:2 輸入數列的項數:6 (11, 36.0) 等差數列的末項為 11,和為 36 自訂函式 4/8 26
  • 27. ? 無傳回值的函式呼叫 ? 函式名稱(引數1, 引數2, ...) ? 將呼叫敘述端的實引數傳給被呼叫函式端的虛引數。虛引數將所得到的 資料帶入函式內經過運算處理後,不回傳結果到原來的呼叫敘述 def printChar(ch, n): for i in range(n): print ('%s' %ch, end = '') print() ch1 = 'A' n1 = 12 printChar(ch1, n1) #以變數作為實引數 printChar('-', 15) #以常值作為實引數 printChar('B', n1) #以常值與變數作為實引數 測試結果: AAAAAAAAAAAA --------------- BBBBBBBBBBBB 自訂函式 5/8 27
  • 28. ? 撰寫函式使用說明 ? 在函式開頭使用「'''」撰寫函式的說明文件,說明文件可以跨行,直到 找到下?個「'''」 ? 可用以下指令讀取函式的說明文件 ? help (函式名稱) ? print (函式名稱.__doc__) 自訂函式 6/8 28
  • 29. ? 為 progression 函式加入說明 def progression(a1, d, n): ''' progression(a1, d, n)函式用來計算等差級數 Args: a1: 等差級數首項 d: 等差級數公差 n: 等差級數項數 Returns: 回等差級數未項值及總和 ''' an = a1 + (n - 1) * d #末項 sn = n * (a1 + an) / 2 #和 return an, sn help(progression) 自訂函式 7/8 29
  • 30. 測試結果: Help on function progression in module __main__: progression(a1, d, n) progression(a1, d, n)函式用來計算等差級數 Args: a1: 等差級數首項 d: 等差級數公差 n: 等差級數項數 Returns: 回等差級數未項值及總和 自訂函式 8/8 30
  • 31. ? 設計程式計算二正整數之最大公因數與最小公倍數 ? 歐幾里得演算法 (Euclidean Algorithm),也稱為輾轉相除法,用來計算兩 個整數的最大公因數(GCD,Greatest Common Divisor) gcd ?, ? gcd ?, ? , ? ? ?, ? 0 gcd ?, ?%? , ???? ? 最小公倍數(LCM,Least Common Multiple) ??? ? ? ??? lcm(32, 12) = 32 * 12 / 4 = 96 實作練習 1/2 2 32 12 1 24 8 2 8 4 8 0 2 32 12 24 8 2 32 12 1 24 8 8 4 被除數 除數 被除數 除數 除數即為最 大公因數 被除數 31 整除
  • 32. def gcd(x, y): while ( x > 0 and y > 0 ): if(x > y): x = x % y else: y = y % x return y if (x == 0) else x while True: a = eval(input('輸入第?個正整數a:')) b = eval(input('輸入第二個正整數b:')) if a > 0 and b > 0: break else: print('無效輸入, 請重新輸入...') gcd = gcd(a, b) print('%d, %d 兩整數的GCD為 %d' %(a, b, gcd)) print('%d, %d 兩整數的LCM為 %d' %(a, b, (a * b)/gcd)) 測試結果: 輸入第?個正整數a:234 輸入第二個正整數b:36 234, 36 兩整數的GCD為 18 234, 36 兩整數的LCM為 468 實作練習 2/2 32
  • 33. ? 設計解?元二次方程式的兩個根的函式,由使用者輸入方程式的平方 項係數 a、?次項係數 b、及常數項 c,先判斷所輸入的?元二次方程 式係數是否有實數解,再呼叫自訂函式求解 ? ?元二次方程式:?? ?? ? 0 ? 實數解條件:? 4?? 0 ? 實數解? 實作練習 1/2 33
  • 34. import math def equation(a, b, c): d = math.sqrt(b ** 2 – 4 * a * c) return (-b + d)/(2 * a), (-b - d)/(2 * a) while (1): a = eval(input('請輸入平方項係數a:')) b = eval(input('請輸入?次項係數b:')) c = eval(input('請輸入常數項c:')) if ((b ** 2 – 4 * a * c) >= 0): break else: print('無解, 請重新輸入係數...') ret = equation(a, b, c) print('?元二次方程式的根為 %0.2f, %0.2f' %(ret[0], ret[1])) 測試結果: 請輸入平方項係數a:2 請輸入?次項係數b:3 請輸入常數項c:1 ?元二次方程式的根為 -0.50, -1.00 實作練習 2/2 34
  • 35. ? 呼叫函式時,若引數數量與參數數量不相符,在這種情況下?般是會 產生錯誤的 ? 要避免上述錯誤情形,在定義函式時,可指定參數預設值。如此?來, 若呼叫該函式時沒有傳遞引數,或傳遞的實引數數量少於參數數量時, 參數的預設值就派上用場了 ? 當某?參數定義了預設值,其右側的所有參數都必須定義預設值 def greeting(name, msg = 'Good morning!', msg2 = ''): print('Hello', name + ', ' + msg) greet('Kate') greet('Bruce', 'How do you do?') 測試: Hello Kate, Good morning! Hello Bruce, How do you do? 參數的預設值 35
  • 36. ? 呼叫函式時引數資料的傳遞方式有傳值呼叫 (call by value) 和參考呼 叫 (call by reference) 兩種 ? 傳值呼叫 ? 虛引數的資料異動時,會另外建立新的資料物件,不會影響到實引數的資 料內容 ? 以下資料型別之引數採用傳值呼叫 boolean, int, float, long, str, unicode, tuple 引數的傳遞方式 1/9 36
  • 37. def inc(x): print('id of x = %d' %id(x), end = ', ') print('x = %d' %(x)) x += 1 print('id of x = %d' %id(x), end = ', ') print('x = %d' %(x)) a = 10 print('id of a = %d' %id(a), end = ', ') print('a = %d' %(a)) inc(a) print('id of a = %d' %id(a), end = ', ') print('a = %d' %(a)) 測試結果: id of a = 140729614147616, a = 10 id of x = 140729614147616, x = 10 id of x = 140729614147648, x = 11 id of a = 140729614147616, a = 10 引數的傳遞方式 2/9 37
  • 38. 引數的傳遞方式 3/9 ? 參考呼叫 ? 實引數和虛引數共用相同資料物件,如此引數間的資料傳遞是雙向互通 ? 在函式中更新虛引數的內容,則原呼叫敘述實引數的內容也跟著變動 ? 以下資料型別之引數採用參考呼叫 list, dict, set 38
  • 39. def additem(x): print('id of x = %d' %id(x), end = ' ,') print('x = ', x) x.append(5) print('id of x = %d' %id(x), end = ' ,') print('x = ', x) a = [1, 2, 3, 4] print('id of a = %d' %id(a), end = ' ,') print('a = ', a) additem(a) print('id of a = %d' %id(a), end = ' ,') print('a = ', a) 測試結果: id of a = 2398559902016 ,a = [1, 2, 3, 4] id of x = 2398559902016 ,x = [1, 2, 3, 4] id of x = 2398559902016 ,x = [1, 2, 3, 4, 5] id of a = 2398559902016 ,a = [1, 2, 3, 4, 5] 引數的傳遞方式 4/9 39
  • 40. ? 在定義函式時,允許不限定傳送過來的實引數數量 ? def 函式名稱(*參數): 程式區塊 [return 回傳值1, 回傳值2…] ? 呼叫函式時,不限定實引數個數,實引數間以逗號分隔 ? 全部的實引數全被封裝成?個元組資料 (tuple) 傳給參數 ? 元組資料的取用方式與串列資料相同 引數的傳遞方式 5/9 40
  • 41. def calsum(*data): total = 0 for x in data: total += x return total print("不定數目引數範例:") print("2個引數:calsum(4, 5) = %d" % calsum(4, 5)) print("3個引數:calsum(4, 5, 12) = %d" % calsum(4, 5, 12)) print("4個引數:calsum(4, 5, 12, 8) = %d" % calsum(4, 5, 12, 8)) 測試結果: 不定數目引數範例: 2個引數:calsum(4, 5) = 9 3個引數:calsum(4, 5, 12) = 21 4個引數:calsum(4, 5, 12, 8) = 29 引數的傳遞方式 6/9 41
  • 42. ? 使用字典參數 ? def 函式名稱(**參數): 程式區塊 [return 回傳值1, 回傳值2…] ? 呼叫函式時,不限定實引數個數,實引數間以逗號分隔 ? 每個實引數使用「引數名稱 = 引數值」形式 ? 全部的實引數全被封裝為成?個字典資料 (dictionary) 傳給參數 引數的傳遞方式 7/9 42
  • 43. def resume(**data): print(data) print('字典引數範例:') resume(name = 'Justin', age = 23, tel = '1234567') 測試結果: 字典引數範例: {'name': 'Justin', 'age': 23, 'tel': '1234567'} 引數的傳遞方式 8/9 43
  • 44. ? 同時使用不定數目引數及字典參數 ? def 函式名稱(*參數1, **參數2): 程式區塊 [return 回傳值1, 回傳值2…] def resume(*index, **data): print(index) print(data) for key in index: print(data[key]) print('同時使用不定數目引數及字典引數範例:') resume('name', 'age', 'tel', name = 'Justin', age = 23, tel = '1234567') 測試結果: 同時使用不定數目引數及字典引數範例: ('name', 'age', 'tel') {'name': 'Justin', 'age': 23, 'tel': '1234567'} Justin 23 1234567 引數的傳遞方式 9/9 44
  • 45. ? 定義在函式外的變數可供多個函式共同使用,稱為「全域變數」 (Global variable),在程式結束前會?直存在 ? 在函式內建立的變數,稱為區域變數 (Local Variable) ? 區域變數僅限在所屬函式中使用,離開該函式時此類變數的記憶體會立即 被釋放掉。每次函式被呼叫時,系統會重新配置記憶體給此類變數使用 ? 由於 Python 會自動建立變數,當函式內的區域變數名稱與全域變數 名稱相同,在函式內會產生「變數覆蓋」的現象 ? 兩個同名稱的變數,在記憶體內是佔用不同的位址,互不影響 ? 當程式流程執行到函式時,就使用這個區域所建立的區域變數,全域變數 會保留其值,等程式流程離開這個函式時,這個區域變數便會消失 ? 待程式流程回到主程式時,全域變數會仍用原保留的值繼續運作 全域變數與區域變數 1/3 45
  • 46. def mysub(): v2, v3 = 200, 300 #Python自動建立v2,v3區域變數 print('--in mysub--') print('v1=%d, v2=%d, v3=%d' %(v1, v2, v3)) #v1是全域變數,v2與v3是區域變數 print('--in main program--') v1, v2 = 10, 20 print('v1=%d, v2=%d' %(v1, v2)) mysub() print('--in main program--') print('v1=%d, v2=%d' %(v1, v2)) print('v1=%d, v2=%d, v3=%d' %(v1, v2, v3)) #錯誤 測試結果: --in main program-- v1=10, v2=20 --in mysub-- v1=10, v2=200, v3=300 --in main program-- v1=10, v2=20 全域變數與區域變數 2/3 46 NameError: name 'v3' is not defined
  • 47. ? 若函式內須要更新全域變數內容,則函式須用 global 來宣告該全域變數 def mysub(): global v2 v2, v3 = 200, 300 #v2為全域變數,並自動建立v3區域變數 print('--in mysub--') print('v1=%d, v2=%d, v3=%d' %(v1, v2, v3)) print('--in main program--') v1, v2 = 10, 20 print('v1=%d, v2=%d' %(v1, v2)) mysub() print('--in main program--') print('v1=%d, v2=%d' %(v1, v2)) 測試結果: --in main program-- v1=10, v2=20 --in mysub-- v1=10, v2=200, v3=300 --in main program-- v1=10, v2=200 全域變數與區域變數 3/3 47
  • 48. ? Lambda函式是?種特別的函式 ? 它是匿名函式,不需要定義名稱,且函式程式碼只能有?行指令敘述。語 法如下: lambda 參數1, 參數2, ...:程式碼 ? 下列max()函式會回傳二數中較大者 def max(m, n): if m > n: return m else: return n 可改寫如下 def max(m, n): return m if m > n else n lambda函式 1/5 48
  • 49. ? 若將max()函式轉換成lambda函式,程式如下 max = lambda m, n : m if m > n else n print(max(10, 3)) ? Lambda函式支援IIFE (immediately invoked function expression) 語 法,意思是利用 function expression 的方式來建立函式,並且立即執 行它,語法如下: ? (lambda 函式參數:指令敘述)(實引數) print((lambda m, n:m if m > n else n)(10, 3)) lambda函式 2/5 49
  • 50. ? Lambda函式通常應用在以下情境 ? function使用頻率偏低,不易命名,或是命名會干擾整個命名規則,採用 隨用隨扔的lambda函式,可節省記憶體 ? filter()函式在可疊代的物件中,依據條件運算式,篩選特定的元素。 語法如下: ? filter(篩選函式, 可疊代的物件) ? 下列程式會篩選串列中的偶數資料 def even_fn(x): return (x % 2 == 0) data = [-5, 1, 3, 2, 5, -9, 20, 21] result = list(filter(even_fn, data)) ? 當需要許多不同的篩選條件時 (奇數、偶數、正數、負數…),我們就要定 義各種篩選函式 lambda函式 3/5 50
  • 51. def even_fn(x): return (x % 2 == 0) def odd_fn(x): return (x % 2 != 0) def positive_fn(x): return (x > 0) data = [-5, 1, 3, 2, 5, -9, 20, 21] result = list(filter(even_fn, data)) print(result) result = list(filter(odd_fn, data)) print(result) result = list(filter(positive_fn, data)) print(result) 測試結果: [2, 20] [-5, 1, 3, 5, -9, 21] [1, 3, 2, 5, 20, 21] lambda函式 4/5 51
  • 52. ? 每個篩選運算式其實都很簡單,要為不同篩選條件定義函式並命名也會有 點困擾,此時就很適合改用lambda函式 data = [-5, 1, 3, 2, 5, -9, 20, 21] result = list(filter(lambda x: x % 2 == 0, data)) print(result) result = list(filter(lambda x: x % 2 != 0, data)) print(result) result = list(filter(lambda x: x > 0, data)) print(result) 測試結果: [2, 20] [-5, 1, 3, 5, -9, 21] [1, 3, 2, 5, 20, 21] lambda函式 5/5 52
  • 53. ? Python的函式本?就是?個物件,因此具備物件的性質 ? 可以將函式設定給?個變數 def ctof(c): return c * 1.8 + 32 fahrenheit = ctof print(fahrenheit(25)) 測試結果: 77.0 ? 可以在函式裡再定義另?個函式 def fahrenheit(c): def ctof(c): return c * 1.8 + 32 print('華氏溫度為:%5.1f 度' % ctof(c)) fahrenheit(25) 測試結果: 華氏溫度為: 77.0 度 笔测迟丑辞苍函式的其它特性 1/4 53
  • 54. ? 函式可以當做參數傳給另?個函式 def jap(): print('こんにちは, ', end = '') def eng(): print('Hello, ', end = '') def cht(): print('你好, ', end = '') def vietnam(): print('xin chào, ', end = '') def sayhello(name, nationality): nationality() print(name) funcs = [cht, eng, jap, vietnam] name = input('Name: ') i = int(input('Nationality 1-Chinese, 2-English, 3-Japanese, 4-Vietnam:')) sayhello(name, funcs[i - 1]) 測試結果: Name: Tony Nationality 1-Chinese, 2-English, 3-Japanese, 4-Vietnam:1 你好, Tony 笔测迟丑辞苍函式的其它特性 2/4 54
  • 55. ? 函式可以回傳另?個函式 def nationality(i): def jap(): print('こんにちは, ', end = '') def eng(): print('Hello, ', end = '') def cht(): print('你好, ', end = '') def vietnam(): print('xin chào, ', end = '') funcs = [cht, eng, jap, vietnam] return funcs[i - 1] def sayhello(name, greeting): greeting() print(name) name = input('Name: ') i = int(input('Nationality 1-Chinese, 2-English, 3-Japanese, 4-Vietnam:')) sayhello(name, nationality(i)) 笔测迟丑辞苍函式的其它特性 3/4 55
  • 56. ? 內部函式可以取得包含函式的區域變數 def greeting(name, i): def jap(): print('こんにちは! ', name) def eng(): print('Hello! ', name) def cht(): print('你好! ', name) def vietnam(): print('xin chào, ', end = '') funcs = [cht, eng, jap, vietnam] funcs[i - 1]() name = input('Name: ') i = int(input('Nationality 1-Chinese, 2-English, 3-Japanese, 4-Vietnam:')) greeting(name, i) 測試結果: Name: Tony Nationality 1-Chinese, 2-English, 3-Japanese, 4-Vietnam:1 你好, Tony 笔测迟丑辞苍函式的其它特性 4/4 56
  • 57. ? 函式裝飾器 (decorator) 功能是將?個函式的結果,再以另?個函式包 裝處理,使原函式呈現另?種功能面貌 def sayHello(name): return 'Hello, ' + name def htmlText(func): def wrapper(name): return '<p>' + func(name) + '</p>' return wrapper mysayHello = htmlText(sayHello) print(mysayHello('John')) 測試結果: <p>Hello, John</p> ? sayHello函式被當作參數傳入htmlText函式,htmlText函式以內部函式 wrapper來增加sayHello函式的功能,因此htmlText函式裝飾了sayHello 函式,所以htmlText函式就是?個裝飾器 函式裝飾器 1/3 57
  • 58. ? 如要將裝飾器B永遠附加在函式A,需要將執行裝飾函式敘述修改如下: A = B(A),先前程式可修改如下 def sayHello(name): return 'Hello, ' + name def htmlText(func): def wrapper(name): return '<p>' + func(name) + '</p>' return wrapper mysayHello = htmlText(sayHello) print(mysayHello('John')) 測試結果: <p>Hello, John</p> 函式裝飾器 2/3 58
  • 59. ? Python 提供更簡潔的裝飾器語法,在被裝飾的函式前,加上@符號及 裝飾器名稱,就不需要執行附加裝飾器 A = B(A) 的指令 ? @裝飾器 def 被裝飾函式(): def htmlText(func): def wrapper(name): return '<p>' + func(name) + '</p>' return wrapper @htmlText def sayHello(name): return 'Hello, ' + name print(sayHello('John')) 測試結果: <p>Hello, John</p> 函式裝飾器 3/3 59
  • 60. ? 函式間可以相互呼叫,除了呼叫別的函式外,也可呼叫自己本?,這 種函式呼叫自己的方式稱為「遞迴」 ? 遞迴是?種應用極廣的程式設計技術,在函式執行的過程不斷地的呼 叫函式自?,但每?次呼叫,會完成整體之部份作業,直到遇到終止 再呼叫函式自?的條件時,才會停止遞迴逐層返回 ? 如果?個問題能拆成同形式且較小範圍時,就非常適合使用遞迴函式 來設計 ? 例如要計算1 + 2 … + 10的總和時,可以拆成1和2 + 3 … +10;2 + 3 … + 10 又可以拆成2和3 + 4 … + 10,其餘類推,此時就可以設計成遞迴函式 ? 數列、階乘、費氏級數、輾轉相除法、排列、組合、堆疊、河內塔、八個 皇后、樹的走訪、老鼠走迷宮…等問題都具備這種特性 ? 如果遞迴的函式內沒有設定終止呼叫的條件,則這樣的函式會形成無 窮遞迴,造成程式無法正常結束 何謂遞迴 60
  • 61. ? 計算 sum = 1 + 2 + 3 + ... + (n-1) + n 數列總和 ? sum(n) = 1 for n == 1 ? sum(n) = n + sum(n-1) for n > 1 def f(n): if n == 1: return 1 else : #n > 0 return n + f(n - 1) n = eval(input('n = ')) sum = f(n) print('1 + 2 + ... + %d = %d' %(n, sum)) 測試結果: n = 5 1 + 2 + ... + 5 = 15 遞迴應用實例 1/12 遞迴公式 61
  • 62. ? sum(5)執行流程 遞迴應用實例 2/12 sum(5) 5 + sum(4) 4 + sum(3) 3 + sum(2) 2 + sum(1) 1 1 3 6 10 15 62
  • 63. ? 計算 sum = 1 – 4 + 7 – 10 + ... – (n-3) + n 數列總和 ? sum(n) = 1 for n == 1 ? sum(n) = (1 + 3(n-1)) + sum(n-1) for n == 奇數 ? sum(n) = -(1 + 3(n-1)) + sum(n-1) for n == 偶數 def g(n): if (n == 1): return 1 elif (n % 2 == 0): #n > 0,為偶數 return -(1 + 3 * (n - 1)) + g(n - 1) else: #n > 0,為奇數 return 1 + 3 * (n - 1) + g(n - 1) n = eval(input('n = ')) sum = g(n) if (n % 2 == 1): #n輸入值為奇數 print('1 – 4 + 7 – ... + %d = %d' %(1 + 3 * (n - 1), sum)) else: #n輸入值為偶數 print('1 – 4 + 7 – ... - %d = %d' %(1 + 3 * (n - 1), sum)) 遞迴應用實例 3/12 63
  • 64. ? 計算 n! = n * (n-1) * (n-2) * ... * 1 乘積 ? n! = 1 for n <= 1 ? n! = n + (n-1)! for n > 1 def factorial(n): if n <= 1: return 1 else : #n > 1 return n * factorial(n - 1) while True: n = eval(input('n = ')) if (n >= 1): break else: print('輸入資料不符, 請重新輸入...') print('%d! = %d' %(n, factorial(n))) 測試結果: n = 4 4! = 24 遞迴應用實例 4/12 64
  • 65. ? 輾轉相除法就是將兩數相除,能整除則除數為最大公因數;不能整除, 則除數變為被除數,餘數變為除數,再將兩數相除,以此類推 def GCD(p, q): if (p % q == 0): return q else : return GCD(q, p % q) x = eval(input('x = ')) y = eval(input('y = ')) if (x < y): x, y = y, x gcd = GCD(x, y) print('GCD(%d, %d) = %d' %(x, y, gcd)) 測試結果: x = 234 y = 48 GCD(234, 48) = 6 遞迴應用實例 5/12 gcd p, ? ? ?%? 0 gcd ?, ?%? ?%? 0 65
  • 66. ? ?元1200年代的歐洲數學家Fibonacci提出假說: ? 若有?對免子每個月生?對小免子,兩個月後小免子也開始生產。前兩個 月都只有?對免子,第三個月就有兩對免子,第四個月有三對免子,第五 個月有五對免子… ? 假設免子都沒有死亡,則每個月免子的總對數就形成了?種數列,即為 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ... ? 這種數列被稱為「費氏數列」 遞迴應用實例 6/12 ? 0 ? 0 1 ? 1 ? ? ? 2 66
  • 67. def fib(n): if (n == 0): return 0 elif (n == 1): return 1 else: #n >= 2 return fib(n - 1) + fib(n - 2) n = eval(input('n = ')) print('費氏數列第 %d 項為 %d' %(n, fib(n))) 測試結果: n = 10 費氏數列第 10 項為 55 遞迴應用實例 7/12 67
  • 68. ? 有n個不同的物品,要挑出 k 個的方法數有幾個?這是數學上「組合」 的題目,我們用 C(n, k) 來表示。若有針對某個特定物品,會分成兩種 互斥情況: 1. 選到這個特定物品,就再從剩下的n-1個物品中挑出k-1個物品,則會有 C(n-1, k-1)個方法數 2. 沒有選到這個特定物品,就再從剩下的n-1個物品中挑出k個物品,則會有 C(n-1, k)個方法數 ? 所以,當 n = k 或 k = 0 時,則 C(n, k) = 1; 當 n > k 時,則 C(n, k) = C(n-1, k-1) + C(n-1, k) 遞迴應用實例 8/12 68
  • 69. def C(n, k): if n == k or k == 0: return 1 else : return C(n - 1, k - 1) + C(n - 1, k) while True: n = eval(input('n = ')) k = eval(input('k = ')) if n >= 0 and k >= 0 and n > k: break else: print('輸入資料不符, 請重新輸入...') ans = C(n, k) print('組合 C(%d, %d) = %d' %(n, k, ans)) 測試結果: n = 5 k = 2 組合 C(5, 2) = 10 遞迴應用實例 9/12 69
  • 70. ? 河內塔問題 有三根杆子A,B,C。A杆上有 N 個 (N>1) 穿孔圓盤,盤的尺寸由下到上依 次變小。要求按下列規則將所有圓盤移至 C 杆: ? 每次只能移動?個圓盤 ? 大盤不能疊在小盤上面 ? 提示:可將圓盤臨時置於 B 杆,也可將從 A 杆移出的圓盤重新移回 A 杆, 但都必須遵循上述兩條規則 遞迴應用實例 10/12 70 A B C A B C
  • 71. ? 將?個 N 層河內塔由 A 桿移到 C 桿。依照上面的解法 ? 先將前 N-1 層的圓盤先移到 B 桿 ? 再將第 N 層的圓盤移到 C 桿 ? 將 B 桿上的圓盤全部移到 C 桿 遞迴應用實例 11/12 71
  • 72. def Hanoi(n, a, b, c): if n == 1: print('move %d %s --> %s' %(n, a, c)) return Hanoi(n - 1, a, c, b) print('move %d %s --> %s' %(n, a, c)) Hanoi(n - 1, b, a, c) n = int(input('Number of rings on A: ')) Hanoi(n, 'A', 'B', 'C') 測試結果: Number of rings on A: 3 move 1 A --> C move 2 A --> B move 1 C --> B move 3 A --> C move 1 B --> A move 2 B --> C move 1 A --> C 遞迴應用實例 12/12 72
  • 73. ? 在執行遞迴的過程中,系統必須使用堆疊記錄每?層的中間值,然後 去下?層繼續進行計算,直到終止條件被滿?。然而,萬?計算量太 大、或設計不良使得終止條件?直沒有被滿?,就會造成系統資源被 recursion 耗盡 ? 為了避免這件事情的發生,Python 對於遞迴次數 (深度) 有所限制, 也就是說,它透過限制呼叫遞迴函式的次數,來杜絕你的遞迴無止盡 地跑下去這個可能性。透過 sys 模組中的 getrecursionlimit() 函式, 可取得遞迴函式的次數限制, setrecursionlimit()函式可重設遞迴函式 的次數限制 import sys sys.getrecursionlimit() 測試結果: 3000 遞迴限制 73
  • 74. ? 遊戲規則 ? 桌面有?堆?子 ? 遊戲?開始隨機決定該回遊戲之?子總數 (18~23之間) ? 玩家與電腦輪流拿取?子,每回至少要拿?顆,最多可拿N顆 ? 遊戲?開始隨機決定該回遊戲之每回合拿取?子上限值 (3~5) ? 拿到最後?顆?子者落敗 ? 隨機決定誰先拿取?子 應用實例:輪流取物遊戲 1/7 74
  • 75. ? 拿取策略分析 ? 以最多拿3個為例 ? max_take = 3之決策樹 ? max_take + 1為?個完整回合可控制的拿取總數 應用實例:輪流取物遊戲 2/7 玩家 1 2 3 電腦 1~3 1~3 1~3 合計拿取數 2, 3, 4 3, 4, 5 4, 5, 6 75 n-1 n n-2 n-3 n-4 n-3 n-2 n-5 n-6 1 2 3 1 2 3 1 2 3 1 2 3 對手可能拿取數量 自已可以拿取數量
  • 76. ? 1 + (max_take+1) * N組成的節點為關鍵路徑節點 ? take = (total-1) % (max_take + 1) ? 如果計算結果為 0 表示對手佔據關鍵節點,則隨機取 1~max_take ? max_take = 3之決策樹 ? 先佔據關鍵節點者,就能掌控遊戲 應用實例:輪流取物遊戲 3/7 76 1 3 4 5 11 7 9 6 8 3 2 1 1 2 3 10 12 1 2 3 2 3 2 1 1 2 3 對手可能拿取數量 對手可能拿取數量
  • 77. ? 亂數決定?子總數 import random total = random.randint(18, 23) #隨機產生18~23的?子數 ? 亂數決定每回合可拿取的?子上限 max_take = random.randint(3, 5) #隨機產生3~5間的拿取上限值 ? 顯示遊戲訊息 print('共有%d個?子,每回只能拿取1~%d個,拿到最後?個?子者落敗' %(total, max_take)) ? 回合制處理作業 turn = random.randint(0, 9) % 2 #隨機決定誰先,0電腦, 1玩家 if (turn == 1): print('玩家先') else: print('電腦先') 應用實例:輪流取物遊戲 4/7 77
  • 78. ? 玩家回合作業 def player_turn(): global total run = True while (run): try: take = int(input('要取走幾個?子頭(1~%d):' %max_take)) if (take >= 1 and take <= max_take): run = False total = total - take print('玩家取走%d個?子,剩下%d個' %(take, total)) else: print('只能取走1~%d個?子' %max_take) except: print('必須輸入數值') 應用實例:輪流取物遊戲 5/7 78
  • 79. ? 電腦回合作業 def computer_turn(): global total take = (total - 1) % (max_take + 1) if (take == 0): take = random.randint(1, max_take) total = total - take; print('電腦取走%d個?子,剩下%d個' %(take, total)) 應用實例:輪流取物遊戲 6/7 79
  • 80. ? 主程式 while(True): if (turn): player_turn() turn = 1 - turn #換手 if (total == 1): print('玩家獲勝') break else: computer_turn() turn = 1 - turn #換手 if (total == 1): print('電腦獲勝') break 應用實例:輪流取物遊戲 7/7 80
  • 81. ? 遊戲規則 ? 電腦與玩家各自設定?組4位數不重複的數值為謎底 ? 玩家與電腦輸流猜對手數值,對家必須依據自已的答案提供正確提示 ? 玩家先猜 ? A代表數字正確位置也正確,B代表數字正確但位置錯誤 ? 例如正確答案為 5234,而對手猜 5346時,其中 5 的位置對了,記為1A; 3 和 4 這兩個數字對了,而位置不對,記為2B;因此要提示1A2B ? 先猜中對手答案者獲勝 應用實例:猜數字遊戲 1/11 81 5 2 3 4 5 3 4 6 結果為1A2B 答案值 猜測值
  • 82. ? 電腦猜數字策略 1. 前二次固定猜 1357 及 8642 收集答案提示 2. 之後由 9876 開始遞減,搜尋符合下列條件的可能答案 1) 4 個位數之數字不重複 2) 與之前記錄中的猜測值比對,必須得到與記錄中相同的答案題示 3. 如果答錯則增加?組猜測值與答案提示記錄,回到步驟 2 應用實例:猜數字遊戲 2/11 82
  • 83. from random import sample count = 0 #局數 randNum = sample('0123456789', 4) #隨機取出4個數字 answer = ''.join(randNum) #轉換為數字字串 guess = 9876 #電腦猜測值 playerNums = [] #用來記錄玩家每?回合的猜測值 playerHints = [] #用來記錄玩家每?回合的猜測結果 computerNums = [] #用來記錄電腦每?回合的猜測值 computerHints = [] #用來記錄電腦每?回合的猜測結果 應用實例:猜數字遊戲 3/11 83
  • 84. #顯示所有回合猜測值及結果 def show_detail(guesslist, resultlist): for i in range(len(guesslist)) : print ('(%d) %s/%s' % (i + 1, guesslist[i], resultlist[i])) #比對guess與answer數值字串內容,回傳?A?B之a, b值 def check(guess, answer): a = b = 0 for i in range(4): if guess[i] in answer: if i == answer.find(guess[i]) : a += 1 else: b += 1 return a, b 應用實例:猜數字遊戲 4/11 84
  • 85. #找下?組數值不重複的4位數數值字串 def next_guess(): global guess if (guess < 123): print('提示有誤,請重新檢查') sys.exit() while (True): temp = guess tempguess = ['0', '0', '0', '0'] for i in range(3, -1, -1): tempguess[i] = chr(temp % 10 + 48) temp //= 10 computer_guess = ''.join(tempguess) for ch in computer_guess: #檢查數字字串是否有重複的數字 if (computer_guess.count(ch) > 1): guess -= 1 #換下?個數字 break; else: return computer_guess #回傳猜測值 應用實例:猜數字遊戲 5/11 85
  • 86. #驗證猜測值的合理性,假設猜測值為正確答案,那麼與先前所有猜測值應得到同樣的比對結果 def is_reasonable(numstr): for c in range(len(computerNums)): a, b = check(numstr, computerNums[c]) if ((chr(a + 48) != computerHints[c][0]) or (chr(b + 48) != computerHints[c][2])): return False #與先前比對結果不吻合 return True 應用實例:猜數字遊戲 6/11 86
  • 87. #玩家回合處理作業 def player_turn(): wellform = False while (wellform == False): user_guess = input('輸入四個不重複數字:') if (user_guess.isdigit() == False) : print ('***錯誤:只能輸入數字,請重新輸入') continue if (len(user_guess) != 4) : print ('***錯誤:必須輸入四個數字,請重新輸入') continue for ch in user_guess: #檢查是否有重複的數字 if (user_guess.count(ch) > 1): print ('***錯誤:數字不可重複,請重新輸入') break else: wellform = True 應用實例:猜數字遊戲 7/11 87
  • 88. a, b = check(user_guess, answer) #檢查猜測結果 result = '%dA%dB' %(a, b) print(result) playerNums.append(user_guess) #記錄猜測值 playerHints.append(result) #記錄答案提示 return (a == 4) 應用實例:猜數字遊戲 8/11 88
  • 89. #電腦回合處理作業 def computer_turn(): global guess if (count == 0): computer_guess = '1357' elif (count == 1): computer_guess = '8642' else: validate = False while (validate == False): computer_guess = next_guess() if (is_reasonable(computer_guess)): validate = True else: guess -= 1 #換下?組數值 print('電腦猜%s' %computer_guess) 應用實例:猜數字遊戲 9/11 89
  • 90. a = int(input('有幾個數字及位置都正確?')) b = int(input('有幾個數字正確,但位置不正確?')) result = '%dA%dB' %(a, b) print(result) if (a == 4): return True else: computerHints.append(result) #記錄猜測提示 computerNums.append(computer_guess) #記錄猜測結果 guess -= 1 return False 應用實例:猜數字遊戲 10/11 90
  • 91. #主程式 while (True): print ('-' * 20) print('player's turn') show_detail(playerNums, playerHints) if (player_turn()): print ('Congratulations! Your are winner !!') break; print ('-' * 20) print('computer's turn') show_detail(computerNums, computerHints) if (computer_turn()): print ('Computer wins this game !!') break; count += 1 應用實例:猜數字遊戲 11/11 91
  • 92. ? 程式中若要使用math套件的sqrt函式,又要使用squareRoot別名,則 下列匯入敘述何者正確? A. from math.sqrt as squareRoot B. from math import sqrt as squareRoot C. import math.sqrt as squareRoot D. import sqrt from math as squareRoot 自我評量 1/9 92
  • 93. ? 在程式中要從10~20之間隨機產生?整數,下列何者正確? A. random.randint(10, 20) B. random.randrange(10, 20, 1) C. random.randint(10, 21) D. random.randrange(11, 21, 1) 自我評量 2/9 93
  • 94. ? 在程式中要從0.0~1.0之間隨機產生?浮點數,下列何者正確? A. random.randint(0, 1) B. random.randrange(0.0, 1.0) C. random.random(0, 1) D. random.random() 自我評量 3/9 94
  • 95. ? 要隨機產生?個整數,但這個整數必須符合下列條件 ? 數字是3的倍數 ? 最小數是9 ? 最大數是99 A. import random as R print(R.randint(3, 33) * 3) B. from random import * print(randint(3, 32) * 3) C. from random import randrange print(randrange(3, 99, 3)) D. from random import randrange as rnd print(rnd(3, 99, 3)) 自我評量 4/9 95
  • 96. 自我評量 5/9 ? 設計?函式,傳入引數n為浮點數,回傳值為正整數值,則函式會使用 到下列那些敘述? A. math.abs(n) B. math.fabs(n) C. math.round(n) D. math.float(n) E. math.floor(n) F. math.ceil(n) G. math.fmod(n) H. math.int(n) 96
  • 97. ? 串列 A = [1,3,9,2,5,8,4,9,6,7],呼叫 f(A, 10) 後,回傳值為何? def f(A, n): index = 0 for i in range(n): if A[i] >= A[index]: index = i return index 1. 1 2. 2 3. 7 4. 9 自我評量 6/9 97
  • 98. ? 給定 g(x) 函式如下,則 g(13) 傳回值為何? def g(x): if (x > 1): return g(x - 2) + 3 return x 1. 16 2. 18 3. 19 4. 22 自我評量 7/9 98
  • 99. 自我評量 8/9 ? 下列程式碼是?個計算n階層的函式,請問要如何修改才能到正確旳結 果? 1. def f(n): 2. fac = 1 3. if (n >= 0): 4. fac = n * f(n - 1) 5. return fac 1. 第2行改為fac = n 2. 第4行改為fac = n * f(n + 1) 3. 第3行改為if (n > 0): 4. 第4行改為fac = fac * f(n - 1) 99
  • 100. 自我評量 9/9 ? 給定下列g()函式及k()函式,執行g(3)後的傳回值為何? def k(a, n): if (n >= 0): return (k(a, n - 1) + a[n]) else: return 0 def g(n): a = [5, 4, 3, 2, 1] return k(a, n) 1. 5 2. 12 3. 14 4. 15 100