譯自:http://www.honors.montana.edu/~jjc/easytut/easytut/node2.html

Python 非編程員教學

內容





前言

概述:

Python 非編程員教學旨在簡介 Python 編程語言,本教學為沒有編程經驗的人而設。

如果您有其他編程語言的經驗,我建議您看 Guido van Rossum 撰寫的  The Python Tutorial。

本文件有 LATE X, HTML, PDF  及 Postscript 的格式,可往 http://www.honors.montana.edu/~jjc/easytut/ 查看所有這些格式。

假如您有任何問題或建議,可聯絡我 jjc@iname.com,歡迎有關本教學的問題及建議,我會盡我所能解答您任何問題。

感謝 James A. Brown 撰寫大部分 Windows 安裝資料,亦感謝 Elizabeth Cogliati 有關原文的投訴 :) (那對於非編程員來說幾乎不可用)、校對及建議,感謝 Joe Oppegaard 撰寫所有練習,感謝我遺漏了的所有人。

以下是您會覺得有用的一些連結:

獻給 Elizabeth Cogliati


簡介

開始

您從未嘗過編程,在進行這教學時,我會教您如何編程。其實只有一種方法學習編程,就是要看源碼及撰寫源碼。我現在就要您看很多源碼,您要輸入這兒的源碼看看有甚麼發生,研究一下再作一些改變。最壞的情況就是源碼不能運作,當我輸入源碼時,它會格式化如下:

##Python is easy to learn
print "Hello, World!"

那是多麼容易與其他文字分辨開來,要令它混亂,我亦會以同樣字型列印電腦的輸出結果。

現在要繼續更重要的東西,要以 Python 編程,您需要 Python 軟件。如果您仍未有 Python 軟件,可往http://www.python.org/download/ 取得適合您的平台的版本,將它下載,看過指引後再安裝。

安裝 Python

首先您需要從 http://www.python.org/download 為電腦下載正確的檔案,如果您使用的是 Windows,可往 2.0 的連結 (或更新的) 再取得 windows 安裝程式;使用 Unix  可下載 rpm 或源程式碼。

Windows 安裝程式會下載至檔案,透過按兩下已下載的圖示可執行檔安,安裝然後會繼續。

如果您取得 Unix 源程式碼,如果您想使用 IDLE,請確定您以 tk 副檔案編譯。

互動模式

往 IDLE (亦稱為 Python GUI),您應該看到一個視窗有以下的文字:
Python 2.0 (#4, Dec 12 2000, 19:19:57) 
[GCC 2.95.2 20000220 (Debian GNU/Linux)] on linux2
Type "copyright", "credits" or "license" for more information.
IDLE 0.6 -- press F1 for help
>>>
>>> 是 Python 的方式,告訴您在互動模式,在互動模式,您輸入的東西會立即執行。嘗試輸入 1+1 ,Python 會回應 2。互動模式允許您測試及查看 Python 會做些甚麼。如果您曾經覺得有需要研究新的 Python 句式,可往互動模式並嘗試一下。


建立及執行程式

如果您未準備好,可往 IDLE。往 File  再按 New Window,在本視窗輸入以下句子:
print "Hello, World!"

首先儲存程式,往 File 再按 Save ,儲存為  hello.py。(如果您想的話,可將它儲存為預設以外的其他目錄。) 現在它已儲存,可以執行了。

接著透過 Edit 再按 Run script 執行程式,這會在 *Python Shell* 視窗輸出 Hello, World!

仍然有混亂嗎?可嘗試 IDLE 的教學: http://hkn.eecs.berkeley.edu/~dyoo/python/idle_intro/index.html

在指令行使用 Python 

如果您想在指令行使用 Python,您亦沒有需要,只需使用 IDLE。要進入互動模式,只需輸入 python 而無須任何參數。要執行程式,可以文字編輯器建立 (Emacs 有很好的 python 模式) 並以 python 程式名稱執行它。


Hello, World

您需要知道的事情

您應該知道如何在文字編輯器或 IDLE 編輯程式,將它們儲存在磁碟 (軟碟或硬碟),並在儲存後執行它們。

列印

編程教學的開始已由一個名為 Hello, World! 的小程式開始,以下就是該程式:

print "Hello, World!"

假如您使用指令行執行程式,然後以文字編輯器輸入,儲存為 hello.py 並以 ``python hello.py '' 執行。

否則可以往 IDLE,建立新視窗,並建立在 1.4 部分的程式。

當程式執行時,會列印以下一行:

Hello, World!

現在我不會每次也告訴您,但當我向您展示一個程式時,建議您將它輸入及執行。當我輸入一次會學得更好,您亦可能會這樣。

以下是一個更複習的程式:

print "Jack and Jill went up a hill"
print "to fetch a pail of water;"
print "Jack fell down, and broke his crown,"
print "and Jill came tumbling after."

當您執行這程式時,會列印:

Jack and Jill went up a hill
to fetch a pail of water;
Jack fell down, and broke his crown,
and Jill came tumbling after.

當電腦執行這程式時,首先會看到這行:

print "Jack and Jill went up a hill"
因此電腦會列印:
Jack and Jill went up a hill

接著電腦會繼續下一行並看到:

print "to fetch a pail of water;"

因此電腦會在螢幕列印:

to fetch a pail of water;

電腦會繼續查看每行,跟隨指令,並繼續下一行。電腦會繼續執行指令,直至程式結束。

表達式

以下是另一個程式:
print "2 + 2 is", 2+2
print "3 * 4 is", 3 * 4
print 100 - 1, " = 100 - 1"
print "(33 + 2) / 5 + 11.5 = ",(33 + 2) / 5 + 11.5

而以下是程式執行的輸出結果:

2 + 2 is 4
3 * 4 is 12
99 = 100 - 1
(33 + 2) / 5 + 11.5 = 18.5

您會看到 Python 可以將您千元的電腦變為 5 元的計算機。

Python 在數字上有六個基本的操作:

操作 符號 範例
指數 ** 5 ** 2 == 25
乘數
* 2 * 3 == 6
除數 / 14 / 3 == 4
餘數 % 14 % 3 == 2
加數 + 1 + 2 == 3
減數 - 4 - 3 == 1

留意除數會跟隨規則,如果不以小數開始,就沒有小數結束。(注意:在 Python 2.3 會有所改變) 以下的程式會顯示:

print "14 / 3 = ",14 / 3
print "14 % 3 = ",14 % 3
print
print "14.0 / 3.0 =",14.0 / 3.0
print "14.0 % 3.0 =",14 % 3.0
print
print "14.0 / 3 =",14.0 / 3
print "14.0 % 3 =",14.0 % 3
print
print "14 / 3.0 =",14 / 3.0
print "14 % 3.0 =",14 % 3.0
print
輸出結果如下:
14 / 3 =  4
14 % 3 = 2

14.0 / 3.0 = 4.66666666667
14.0 % 3.0 = 2.0

14.0 / 3 = 4.66666666667
14.0 % 3 = 2.0

14 / 3.0 = 4.66666666667
14 % 3.0 = 2.0
留意 Python 如何視乎有沒有使用小數值,而有不同的答案。

操作的次序與數學一樣:

  1. 括弧 ()
  2. 指數 **
  3. 乘數 *, 除數 \, 及餘數 %
  4. 加數 + 及減數 -

與人類溝通 (及其他有智慧的東西)

通常在編程中,您做的都是複雜的東西,而且之後可能不會記得做了些甚麼。如有這樣的情況發生,程式應該被評論。評論就對您及其他編程員解釋正在發生的東西。例如:

#Not quite PI, but an incredible simulation
print 22.0/7.0
留意評論以 # 開始,是用來與其他閱讀這程式的人溝通,以及方便您將來查看。

範例

每章 (最後) 都會有章節中介紹過的編程特點的範例,您最少要看一看是否明白,如果不明白,可能要輸入一次看看有甚麼發生。研究一下再作更改,看看又有甚麼發生。

Denmark.py

print "Something's rotten in the state of Denmark."
print " -- Shakespeare"

輸出結果:

Something's rotten in the state of Denmark.
-- Shakespeare

School.py

#This is not quite true outside of USA
# and is based on my dim memories of my younger years
print "Firstish Grade"
print "1+1 =",1+1
print "2+4 =",2+4
print "5-2 =",5-2
print
print "Thirdish Grade"
print "243-23 =",243-23
print "12*4 =",12*4
print "12/3 =",12/3
print "13/3 =",13/3," R ",13%3
print
print "Junior High"
print "123.56-62.12 =",123.56-62.12
print "(4+3)*2 =",(4+3)*2
print "4+3*2 =",4+3*2
print "3**2 =",3**2
print

Output:

Firstish Grade
1+1 = 2
2+4 = 6
5-2 = 3

Thirdish Grade
243-23 = 220
12*4 = 48
12/3 = 4
13/3 = 4 R 1

Junior High
123.56-62.12 = 61.44
(4+3)*2 = 14
4+3*2 = 10
3**2 = 9

練習

編寫一個程式,以獨立的字串列印您的全名及生日。

編寫一個程式,顯示全部六個數學函式的應用。


當中有甚麼呢?

輸入及變數

現在我覺得是時候做一個真正複雜的程式,如下:
print "Halt!"
s = raw_input("Who Goes there? ")
print "You may pass,", s

當我執行程式,以下是我螢幕的顯示:

Halt!
Who Goes there? Josh
You may pass, Josh

當然,當您執行程式時,螢幕會因 raw_input 句式而有不同。執行程式時可能會留意到 (您已執行了程式,是嗎?) 您要如何輸入您的名字並按 Enter。然後程式會列印更多文字及您的名字,這是輸入的範例,程式達到某一點時,它會等候使用者輸入一些程式稍後會使用的資料。

當然,如果我們沒有地方放置資訊,而這是變數輸入的地方,從使用者取得資訊是沒有用的。在之前的程式中 s 是一個變數,變數就如一個盒,可以儲存一些資料,以下是一個程式,顯示變數的範例:

a = 123.4
b23 = 'Spam'
first_name = "Bill"
b = 432
c = a + b
print "a + b is", c
print "first_name is", first_name
print "Sorted Parts, After Midnight or",b23

輸出結果如下:

a + b is 555.4
first_name is Bill
Sorted Parts, After Midnight or Spam

變數會儲存資料,以上程式中的變數為 a , b23, first_name, b, 及 c,兩個基本的類型為字串和數字,字串是一系列的字母、數字及其他字元。在本例中 b23first_name 是儲存字串的變數,Spam, Bill, a + b isfirst_name 是程式中的字串。字元會由 " ' 包圍,其他類型的變數為數字。

好了,我們有了這些名為變數的盒子,以及會裝入變數的資料,電腦會看到一行如 first_name = "Bill",而它會讀取為 Put the string Bill 放入first_name 的盒子 (或變數)。其後它會看到 c = a + b 句子,並讀取為  Put a + b 或  123.4 + 432 555.4  放入 c

以下是另一個變數應用的範例:

a = 1
print a
a = a + 1
print a
a = a * 2
print a

輸出結果如下:

1
2
4

即使在兩邊有同樣的變數,電腦仍然會讀取為:首先找出要儲存的資料,再找出資料去了甚麼地方。

在結束本章前最後一個程式:

num = input("Type in a Number: ")
str = raw_input("Type in a String: ")
print "num =", num
print "num is a ",type(num)
print "num * 2 =",num*2
print "str =", str
print "str is a ",type(str)
print "str * 2 =",str*2

輸出結果為:

Type in a Number: 12.34
Type in a String: Hello
num = 12.34
num is a <type 'float'>
num * 2 = 24.68
str = Hello
str is a <type 'string'>
str * 2 = HelloHello

num 取得 input, str 會取得 raw_input, raw_input傳回字串時,input 會傳回數字。如您想使用者輸入數字,可使用 input ,但如果您想使用者輸入字串,可使用 raw_input

程式第二部分使用 type,會告訴甚麼是變數。數字是 int float 類型 (分別是 'integer' 及 'floating point' 的縮寫),字串是 string 類型。數字及浮點數可以由算術函數運作,而字串不會。留意 python 將數字乘整數時,預期的事情會如何發生。不過,當字串乘整數時,子串會加上其數量,即 str * 2 = HelloHello

字串的操作與數字的操作稍有不同,以下是一些互動模式範例,顯示更多有關這些。

>>> "This"+" "+"is"+" joined."
'This is joined.'
>>> "Ha, "*5
'Ha, Ha, Ha, Ha, Ha, '
>>> "Ha, "*5+"ha!"
'Ha, Ha, Ha, Ha, Ha, ha!'
>>>

以下是一些字串操作的列表:

操作 符號 範例
重複 * "i"*5 == "iiiii"
結合 + "Hello, "+"World!" == "Hello, World!"

範例

Rate_times.py

#This programs calculates rate and distance problems
print "Input a rate and a distance"
rate = input("Rate:")
distance = input("Distance:")
print "Time:",distance/rate

執行範例:

> python rate_times.py
Input a rate and a distance
Rate:5
Distance:10
Time: 2
> python rate_times.py
Input a rate and a distance
Rate:3.52
Distance:45.6
Time: 12.9545454545

Area.py

#This program calculates the perimeter and area of a rectangle
print "Calculate information about a rectangle"
length = input("Length:")
width = input("Width:")
print "Area",length*width
print "Perimeter",2*length+2*width

執行範例:

> python area.py
Calculate information about a rectangle
Length:4
Width:3
Area 12
Perimeter 14
> python area.py
Calculate information about a rectangle
Length:2.53
Width:5.2
Area 13.156
Perimeter 15.46

temperature.py

#Converts Fahrenheit to Celsius
temp = input("Farenheit temperature:")
print (temp-32.0)*5.0/9.0

執行範例:

> python temperature.py
Farenheit temperature:32
0.0
> python temperature.py
Farenheit temperature:-40
-40.0
> python temperature.py
Farenheit temperature:212
100.0
> python temperature.py
Farenheit temperature:98.6
37.0

練習

編寫程式,從使用者取得兩個字串變數和兩個整數變數,結合 (連接它們而沒有空間) 並顯示字串,再在新一行將兩個數字乘起來。


數至 10

While loops

顯示我們第一個控制結構,電腦一般以第一行開始,再往下看。控制結構會改變句式的次序,句式會被執行或決定會否某個句式會否執行。以下是使用 while 控制結構的程式源碼:

a = 0
while a < 10:
a = a + 1
print a

以下是輸出結果:

1
2
3
4
5
6
7
8
9
10

(當您的電腦成為一個五元的計算機後,您想它不會再差吧?) 那麼程式會做些甚麼?首先它會讀取 a = 0 一行,並令它成為一個零,接著它會讀取 while a < 10:因此電腦會查看 a < 10。電腦第一次看到 a is zero 這句式 ,因此它少於 10。換句話說,當 a 少於 10,電腦會在句式執行 tabbed。

以下是 while 應用的另一個範例:

a = 1
s = 0
print 'Enter Numbers to add to the sum.'
print 'Enter 0 to quit.'
while a != 0 :
print 'Current Sum:',s
a = input('Number? ')
s = s + a
print 'Total Sum =',s

我第一次執行這程式時,Python 會列印:

  File "sum.py", line 3
while a != 0
^
SyntaxError: invalid syntax
我忘了在 while 之後加上:,會有錯誤訊息投訴出現問題,並指出問題可能是有關 SPMquot^"。在問題解決後,以下是我在程式所做的東西:
Enter Numbers to add to the sum.
Enter 0 to quit.
Current Sum: 0
Number? 200
Current Sum: 200
Number? -15.25
Current Sum: 184.75
Number? -151.85
Current Sum: 32.9
Number? 10.00
Current Sum: 42.9
Number? 0
Total Sum = 42.9

留意如何列印'Total Sum =',s 只在結束時才執行。while 句式只會影響 tabbed 了的行 (亦稱為縮排)。!= 表示不等於,因此 while a != 0 : 表示直至 a 是零執行其後 tabbed 了的句子。

現在我們有 while loops,很可能會令程式永遠執行,一個容易的方法是編寫程式如下:

while 1 == 1:
print "Help, I'm stuck in a loop."

這程式會一直輸出 Help, I'm stuck in a loop. 直至世界末日或您停止它才會停下來。停止它的方式就是同時按 Control (或 Ctrl) 按鈕及 `c' (字母),這就能將程式殺掉。 (注意:有時您需要在 Control C 之後按 enter。)

範例

Fibonnacci.py

#This program calulates the fibonnacci sequence
a = 0
b = 1
count = 0
max_count = 20
while count < max_count:
count = count + 1
#we need to keep track of a since we change it
old_a = a
old_b = b
a = old_b
b = old_a + old_b
#Notice that the , at the end of a print statement keeps it
# from switching to a new line
print old_a,
print

輸出結果:

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181

Password.py

# Waits until a password has been entered.  Use control-C to break out with out
# the password

#Note that this must not be the password so that the
# while loop runs at least once.
password = "foobar"

#note that != means not equal
while password != "unicorn":
password = raw_input("Password:")
print "Welcome in"

執行範例:

Password:auo
Password:y22
Password:password
Password:open sesame
Password:unicorn
Welcome in

決定式

If 句式

通常我也相信應該以熱身打字練習開始每個章節,以下就是一個簡短的程式,計算數字的絕對值:
n = input("Number? ")
if n < 0:
print "The absolute value of",n,"is",-n
else:
print "The absolute value of",n,"is",n

以下就是我執行程式兩次的結果:

Number? -34
The absolute value of -34 is 34

Number? 1
The absolute value of 1 is 1

當電腦看到這些源碼時,它會做些甚麼呢?首先會以 n = input("Number? ")句式要求使用者輸入數字,接著會讀取 if n < 0: 一行,如果 n 少於零,Python 會執行 print "The absolute value of",n,"is",-n 一行,否則 python 會執行 print "The absolute value of",n,"is",n 一行。

更正式地 Python 會查看 expression n < 0 屬真屬假,if 句式會由一組句式跟隨,當表達式是真時就會執行,另一個選擇就是 if 句式後的 else  句式,如果句式是假的 else 就會執行。 

一個句式可以有不同的測試,以下是它們所有的列表:

運算符號 函數
< 少於
<= 少於或等於
> 大於
>= 大於或等於
== 等於
!= 不等於
<> 不等於的另一種方式

if 指令的另一種特點是 elif 句式,它代表 for else if ,並表示如果原來的 if 句式是錯誤的,那麼 elif 部分就是真的,以下是一個範例:

a = 0
while a < 10:
a = a + 1
if a > 5:
print a," > ",5
elif a <= 7:
print a," <= ",7
else:
print "Neither test was true"

以下是輸出結果:

1  <=  7
2 <= 7
3 <= 7
4 <= 7
5 <= 7
6 > 5
7 > 5
8 > 5
9 > 5
10 > 5

留意 elif a <= 7 如何只在句式不真實時才會作測試,elif 允許在單一個 if  句式中進行多個測試。

範例

High_low.py

#Plays the guessing game higher or lower 
# (originally written by Josh Cogliati, improved by Quique)

#This should actually be something that is semi random like the
# last digits of the time or something else, but that will have to
# wait till a later chapter. (Extra Credit, modify it to be random
# after the Modules chapter)
number = 78
guess = 0

while guess != number :
guess = input ("Guess a number: ")

if guess > number :
print "Too high"

elif guess < number :
print "Too low"

print "Just right"

執行範例:

Guess a number:100
Too high
Guess a number:50
Too low
Guess a number:75
Too low
Guess a number:87
Too high
Guess a number:81
Too high
Guess a number:78
Just right

even.py

#Asks for a number.
#Prints if it is even or odd

number = input("Tell me a number: ")
if number % 2 == 0:
print number,"is even."
elif number % 2 == 1:
print number,"is odd."
else:
print number,"is very strange."

執行範例。

Tell me a number: 3
3 is odd.

Tell me a number: 2
2 is even.

Tell me a number: 3.14159
3.14159 is very strange.

average1.py

#keeps asking for numbers until 0 is entered.
#Prints the average value.

count = 0
sum = 0.0
number = 1 #set this to something that will not exit
# the while loop immediatly.

print "Enter 0 to exit the loop"

while number != 0:
number = input("Enter a number:")
count = count + 1
sum = sum + number

count = count - 1 #take off one for the last number
print "The average was:",sum/count

執行範例

Enter 0 to exit the loop
Enter a number:3
Enter a number:5
Enter a number:0
The average was: 4.0

Enter 0 to exit the loop
Enter a number:1
Enter a number:4
Enter a number:3
Enter a number:0
The average was: 2.66666666667

average2.py

#keeps asking for numbers until count have been entered.
#Prints the average value.

sum = 0.0

print "This program will take several numbers than average them"
count = input("How many numbers would you like to sum:")
current_count = 0

while current_count < count:
current_count = current_count + 1
print "Number ",current_count
number = input("Enter a number:")
sum = sum + number

print "The average was:",sum/count

執行範例

This program will take several numbers than average them
How many numbers would you like to sum:2
Number 1
Enter a number:3
Number 2
Enter a number:5
The average was: 4.0

This program will take several numbers than average them
How many numbers would you like to sum:3
Number 1
Enter a number:1
Number 2
Enter a number:4
Number 3
Enter a number:3
The average was: 2.66666666667

練習

修改猜密碼的程式,追縱使用者輸入錯誤密碼的次數,假如多於三次,就會列印 ``That must have been complicated.''。

編寫一個程式,要求輸入兩個數字,如果數字的總和大於 100,會列印 ``That is big number''。

編寫一個程式,要求使用者輸入名稱,如果他們輸入您的名稱,說 "That is a nice name",如果他們輸入 "John Cleese" 或 "Michael Palin",告訴他們您對他們的感覺 ;),否則告訴他們 "You have a nice name"。


除錯

甚麼是除錯?

當我們開始編程,會發現要使程式運行,不是我們想像中的容易,我們需要進行除錯,我仍記得當我知道生命的大部分時間就是要找出自己的程式的錯處的那一刻。

- Maurice Wilkes discovers debugging, 1949

現在如果您感到程式有混亂,您可能發現程式有時會做一些您不想它做的事情,這是頗為普遍的。除錯是找出電腦正在做甚麼,以及您想它做甚麼的過程,這可以是很花技巧的,我曾試過花了近一星期追查及解決一個問題,而問題是由某人將 y 當 x 所致。

本章會比之前的章節更抽像,請告訴我是否有用。

程式應該做甚麼?

首要的事情 (這十分明顯) 是要找出程式正確執行時會做些甚麼,做一些測試情況,看看有甚麼會發生。例如我有一個計算長方形周界的程式 (所有邊界的長度總和)﹐測試情況如下:

闊度 高度 周界
3 4 14
2 3 10
4 4 16
2 2 8
5 1 12

我現在於所有測試情況下執行我的程式,並查看程式是否如我預期所做的,如果不是,我需要找出電腦的所做的東西。

更普遍的是有些測試情況會運作,而有些卻不能。如果是那種情況,您應該嘗試和找出可以運作的有甚麼共同的特點。例如以下是周界程式的輸出結果 (您會在一分鐘內看到源碼):

Height: 3
Width: 4
perimeter = 15
Height: 2
Width: 3
perimeter = 11
Height: 4
Width: 4
perimeter = 16
Height: 2
Width: 2
perimeter = 8
Height: 5
Width: 1
perimeter = 8

留意首兩個輸入並不能運作,接著兩個卻沒有問題,最後一個不能運作。嘗試並找出可運作的有甚麼共同的缺點,當您對問題的錯誤有頭緒,要找出原因就容易一點了。如果有需要,可嘗試更多測試條件。

程式做了甚麼?

下一個要做的東西是查看源程式碼,在編程時其中一項要做的最重要事情就是查看源程式碼,主要的方式就是查看源碼。

查看程式就是在第一行開始,它會繼續下去直至程式完成。While loops 及 if 句式表示有些行可能永不會執行,而有些行會執行很多次。在每一行您會找到 Python 做了些甚麼。

現在就以簡單的周界程式開始,不要輸入,您現在就要讀取它,而不是執行它。源程式碼如下:

height = input("Height: ")
width = input("Width: ")
print "perimeter = ",width+height+width+width

問:第一行 Python 會執行甚麼?

答:第一行永遠都會執行,在這情況下是: height =   input("Height: ")

問:那一行做甚麼?

答:列印 Height: ,等候使用者輸入一個數字,並將它放入變數 height。

問:接著執行那行是甚麼?

答:一般來說,那是下一行 width = input("Width: ")

問:那一行做甚麼?

答:列印 Width: ,等候使用者輸入一個數字,並將它放入變數 width。

問:下一行執行的會是甚麼?

答:當下一行比現有的行沒有縮排太多或太少,那就是之後的一行,因此是: print "perimeter = ",width+height+width+width (它可能亦會在現有一行執行一個函式,但那是之後的章節。)

問:那一行做些甚麼?

答:首先它會列印 perimeter =,然後是 width+height+width+width

問:width+height+width+width 會正確計算周界嗎?

答:現在看一看,長方形的周界是底 (闊) 加左邊 (高) 加上 (闊)加右邊 (高)。最後一個項目應該是右邊的長度或高度。

問:您明白為甚麼有時周界的計算會正確嗎?

答:當闊度和高度相等時,計算就會正確。

下一個我們會研究源碼的程式是會在螢幕印出 5 點的程式,不過程式的輸出結果是:

. . . .

程式如下:

number = 5
while number > 1:
print ".",
number = number - 1
print

這個程式較複雜,因為它有縮排的部分 (或控制結構)。現在就開始吧。

問:第一行執行的是甚麼?

答:檔案第一行是: number = 5

問:它會做些甚麼?

答:將數字 5 放在變數。

問:下一行是甚麼?

答:下一行是 while number > 1:

問:它會做些甚麼?

答:while 句式一般會尋找它們的表達式,如果表達式是真的,它們會做下一組縮排的源碼,否則它們會略過下一組縮排的源碼。

問:那麼它現在會做些甚麼?

答:如果 number > 1 是真的,就會執行接著那兩行。

問:那麼 number > 1 嗎?

答:最後一個值會放入 number 的是 5 ,而 5 > 1 因此這是對的。

問:那麼下一行是甚麼?

答:由於 while 是真的,下一行是: print ".",

問:那一行會做甚麼?

答:列印一點,而由於句式以 a 結束,下一行句式不會在第二行。

問:下一行是甚麼?

答:number = number - 1 因為這是接著的行,而沒有縮排的改變。

問:它做些甚麼?

答:它計算 number - 1,那是 number (或 5) 的現有值減一,並使它成為新的 number 數值。因此基本上數字的值由 5 變為 4。

問:下一行是甚麼?

答:縮排的層級減少,因此我們要查看控制結構的類型,那是一個 while loop,因此我們要返回 while 句式,就是 while number > 1:

問:它會做些甚麼?

答:它會查看 number 的值,那就是 4,並將它與 1 比較,由於 4 > 1,while loop 會繼續。

問:下一行會是甚麼?

答:由於while loop 是真的,下一行會是: print ".",

問:它會做甚麼?

答:它會在該行列印第二點。

問:下一行會是甚麼?

答:沒有縮排改變,因此是: number = number - 1

問:它會做甚麼?

答:它會計算 number (4) 的值,再減一,這樣會得出 3,最後會令 3 成為 number 新的值

問:下一行會是甚麼?

答:由於這縮排的改變是因 while loop 結束,下一行是: while number > 1:

問:它會做甚麼?

答:它比較 number (3) 的值及 1. 3 > 1 ,因此 while loop 會繼續。

問:下一行會是甚麼?

答:由於 while loop 條件是真的,下一行是: print ".",

問:它會做甚麼?

答:該行會列印第三點。

問:下一行會是甚麼?

答:那是 number = number - 1

問:它會做甚麼?

答:它會取得 number (3) 現有的值減一,並令 2 成為 number 的新值。

問:下一行會是甚麼?

答:備份至 while loop 的開始:while number > 1:

問:它會做甚麼?

答:它會比較 number (2) 的現有值及 1,由於 2 > 1 ,while loop 會繼續。

問:下一行會是甚麼?

答:由於 while loop 會繼續:print ".",

問:它會做甚麼?

答:它發現了生命、宇宙及所有東西的意義,說笑而已。(我要確定您是清醒的) 該行會在螢幕列印第四點。

問:下一行會是甚麼?

答:那是 number = number - 1

問:它會做甚麼?

答:取得 number (2) 的現有值減一,並使一成為 number 的新值。

問:下一行會是甚麼?

答:備份至 while loop: while number > 1:

問:它會做甚麼?

答:它會比較 number (1) 的現有值及一,由於 > 1 是錯誤的 (一並不比一大),while loop 會離開。

問:下一行會是甚麼?

答:由於 while loop 條件是錯誤的,下一行是 while loop 那一行是離開後的那一行,或: print

問:它會做甚麼?

答:令螢幕往下一行。

問:為甚麼程式不會列印五點?

答:loop 太快離開 1 點。

問:如何解決?

答:令 loop 較遲離開 1。 

問:如何做到?

答:有幾個方法也可以做到,一個方法是更改 while loop 為: while number > 0: 另一個方式是更改條件為: number >= 1 。還有一些其他方法。

如何修補程式?

您需要找出程式在做甚麼,以及程式應該做甚麼?找出兩者的分別,除錯是需要完成需要學習的技巧,假如您在一小時後仍未能找出它們的分別﹐可休息一會,與其他人談談有關的問題,或再仔細想想問題所在。過一會後回來,您可能會對問題有新的意見,祝您好運。


定義函式

建立函數

要開始這章節,我要向您講述一個應該可以做到卻不能做到的範例 (因此不要輸入它來嘗試):
a = 23
b = -23

if a < 0:
a = -a

if b < 0:
b = -b

if a == b:
print "The absolute values of", a,"and",b,"are equal"
else:
print "The absolute values of a and b are different"
輸出結果為:
The absolute values of 23 and 23 are equal
程式似乎有點重複, (編程員討壓重複的東西 (那是電腦的作用,不是嗎?)) 幸好 Python 允許您建立函式移除重複。以下是重寫的範例:
a = 23
b = -23

def my_abs(num):
if num < 0:
num = -num
return num

if my_abs(a) == my_abs(b):
print "The absolute values of", a,"and",b,"are equal"
else:
print "The absolute values of a and b are different"
輸出結果為:
The absolute values of 23 and -23 are equal
這程式的主要功能是 def statement. def (define 的縮寫) 開始一個函式定義, def 會以函式的名稱 my_abs 跟隨,接著而來的是(num 參數跟隨 (當呼叫函式時,num會從程式傳入函式)。當使用函式時,會執行在 : 之後的句式。句式會繼續,直至縮排的句式結束,或遇到 returnreturn 句式會將值傳回函式呼叫的位置。

注意 ab 的值沒有改變,函式當然可以用來重複不會傳回值的工作,以下是一些例子:

def hello():
print "Hello"

def area(width,height):
return width*height

def print_welcome(name):
print "Welcome",name

hello()
hello()

print_welcome("Fred")
w = 4
h = 5
print "width =",w,"height =",h,"area =",area(w,h)
以下是輸出結果:
Hello
Hello
Welcome Fred
width = 4 height = 5 area = 20
該範例只會顯示更多您會以函數做的東西,注意您可以不使用參數或兩個或更多參數,此外亦要留意當函數無須傳回值時﹐return 是可有可無的。

函數中的變數

當然,當消除重複的源碼時,在重複的源碼中通常有變數,這些在 Python 上會以特別的方式處理。直至現在,我們看到的所有變數都是 global 變數,函式有一種特別的類型的變數稱為 local 變數,這些變數只在函式執行時才會存在。當 local 變數與另一個變數有相同的名稱,例如 global 變數,local 變數會隱藏其他變數。感到混亂了嗎?希望下一個範例 (較有目的)能令您的概念清晰一點。

a_var = 10
b_var = 15
e_var = 25

def a_func(a_var):
print "in a_func a_var = ",a_var
b_var = 100 + a_var
d_var = 2*a_var
print "in a_func b_var = ",b_var
print "in a_func d_var = ",d_var
print "in a_func e_var = ",e_var
return b_var + 10

c_var = a_func(b_var)

print "a_var = ",a_var
print "b_var = ",b_var
print "c_var = ",c_var
print "d_var = ",d_var

輸出結果為:

in a_func a_var =  15
in a_func b_var = 115
in a_func d_var = 30
in a_func e_var = 25
a_var = 10
b_var = 15
c_var = 125
d_var =
Traceback (innermost last):
File "separate.py", line 20, in ?
print "d_var = ",d_var
NameError: d_var

在本例中,當變數 a_var, b_var, 及 d_var 在 a_function 函式中,它們全都是 local 變數。當 return b_var + 10 句式執行時,它們全都停止存在。因為變數 a_var 是一個參數名稱,它自動是 local 變數。變數 b_vard_var 是 local 變數,因為它們出現在 b_var = 100 + a_vard_var = 2*a_var 句式中函數等號的左邊。

函數中的 a_var 為 15,因為函數稱為 a_func(b_var)。由於那時 time b_var 是 15,傳叫該函式為 a_func(15),這就會在 a_func 中時結束 a_var 設定為 15。

您會看到,當函式完成執行時, local 變數 a_varb_var 會隱藏同一個名稱的 global 變數。接著句式 print "a_var = ",a_var 會列印值為 10 而不是 15 ,因為隱藏 global 變數的 local 變數會消失。

另一項要留意的東西是在結尾的 NameError,這似乎是因為變數 d_var 自從 a_func 完成後便不在存在。所有 local 變數會在函式離開時刪除,如果您想從函式取得一些東西,那麼您需要使用 return。

最後要留意的一項東西是在a_func 中的 e_var 值保留不變,因為它不是一個參數,而它永不會出現在 a_func 函式中等號的左邊。當 global 變數在函式中存取時,它在外界是 global 變數。

函數允許只存在函式中的 local 變數,而且可以將函數以外的其他變數隱藏。

函數檢查

TODO 將這部分移往新的一章,進階函式。

現在我們會檢查以下程式:

def mult(a,b):
if b == 0:
return 0
rest = mult(a,b - 1)
value = a + rest
return value

print "3*2 = ",mult(3,2)

基本上這程式會建立一個正的數字乘法函式 (那遠比內置的乘法函式慢),然後透過使用這函式作示範。

問:程式首先會做甚麼?

答:首先會做的是用以下幾行定義的 mult 函式:

def mult(a,b):
if b == 0:
return 0
rest = mult(a,b - 1)
value = a + rest
return value
這會建立一個函式,取得兩個參數,並在完成時傳回一個值,之後這函式可以執行。

問:接著會發生甚麼?

答:函式後的下一行,會執行 print "3*2 = ",mult(3,2)

問:這會做甚麼?

答:它會列印 3*2 = 然後傳回 mult(3,2)的值

問: mult(3,2) 會傳回甚麼?

答:我們需要查看 mult 函式找出。

問:接著會發生甚麼?

答:變數 a 會取得 3 ,而變數 b 取得 2。

問:然後怎樣?

答:if b == 0: 一行會被執行,由於 b 的值為 2,這是錯誤的,因此 return 0 一行會被略過。

問:然後又怎樣?

答:rest = mult(a,b - 1)一行會被執行,這行會設定 local 變數 restmult(a,b - 1)的值。a 的值為 3,而 b 的值為 2,因此函式呼叫為 mult(3,1)。

問:那麼 mult(3,1)的值是?

答:我們需要以參數 3 及 1 執行 mult 函式。

問:然後又會怎樣?

答:新執行的函式中的 local 變數會被設定,因此 a 的值為 3,b 的值為 1。由於這些是 local 值,因此不會影響 a 及 b 之前的值。

問:然後呢?

答:由於 b 的值為 1,if 句式是假的,因此下一行變成 rest = mult(a,b - 1)

問:這一行做些甚麼?

答:這一行會為餘下的指派 mult(3,0) 的值。

問:那麼該值是甚麼?

答:我們需要再執行函式一次才能找出,這次 a 的值為 3,b 的值為 0。

問:然後又怎樣?

答:函式執行的第一行if b == 0:b 的值為 0 ,因此下一行要執行的是 return 0

問:return 0 那一行會做甚麼?

答:這行在函式中傳回 0。

問:然後呢?

答:那麼現在我們知道 mult(3,0) 的值為 0,現在我們知道 rest = mult(a,b - 1) 一行做些甚麼,因為我們以參數 3 及 0 執行 mult 函式。我們已完成執行 mult(3,0) 而且返回執行 mult(3,1) 。變數 rest 取得指派的值 0。

問:下一行會執行甚麼?

答:接著會執行 value = a + rest 一行,函式執行時,a=3rest=0 ,因此現在 value=3

問:接著會發生甚麼?

答:return value 一行會執行,這會從函式傳回 3,這亦會從 mult (3,1) 函數離開, return 執行後,我們會返回執行 mult(3,2)。

問:我們在 mult(3,2)哪裡?

答:我們有的變數是 a=3b=2,而且檢查 rest = mult(a,b - 1)一行。

問:因此現在會怎樣?

答:變數 rest 取得 3,下一行 value = a + rest 設定值為 3+3  或  6。

問:因此現在會怎樣?

答:下一行會執行,這會由函式傳回 6,我們現在返回 print "3*2 = ",mult(3,2) 一行,現在可列印 6。

問:整體會怎樣?

答:基本上我們使用兩個事實計算兩個數的乘數,第一個是任何數字乘 0 是 0 (x * 0 = 0),第二個是一個數字乘另一個數字等於第一個數字加第一個數字乘第二個數字減一 ( x * y = x + x * (y - 1))。因此會發生的是 3*2 首先轉換成 3 + 3*1 ,接著 3*1 轉換成 3 + 3*0。接著我們會知道任何數字乘 0 是 0,因此 3*0 是 0。然後我們會計算 3 + 3*03 + 0 就是 3。現在我們知道 3*1 是甚麼,因此我們會計算 3 + 3*1 3 + 3 就是 6

這是整個事情如何運作:

3*2
3 + 3*1
3 + 3 + 3*0
3 + 3 + 0
3 + 3
6

這些最後的兩個部分最近寫入,如果您有任何評論,找到任何錯誤或認為我需要更多/更清晰的解釋,請電郵我。從前我知道令簡單的事情複雜化,如果教學的餘下部分是合理的,而本部分卻不是,這可能是我的錯誤,感謝任何人讓我知道。

範例

factorial.py

#defines a function that calculates the factorial

def factorial(n):
if n <= 1:
return 1
return n*factorial(n-1)

print "2! = ",factorial(2)
print "3! = ",factorial(3)
print "4! = ",factorial(4)
print "5! = ",factorial(5)

輸出結果:

2! =  2
3! = 6
4! = 24
5! = 120

temperature2.py

#converts temperature to fahrenheit or celsius

def print_options():
print "Options:"
print " 'p' print options"
print " 'c' convert from celsius"
print " 'f' convert from fahrenheit"
print " 'q' quit the program"

def celsius_to_fahrenheit(c_temp):
return 9.0/5.0*c_temp+32

def fahrenheit_to_celsius(f_temp):
return (f_temp - 32.0)*5.0/9.0

choice = "p"
while choice != "q":
if choice == "c":
temp = input("Celsius temperature:")
print "Fahrenheit:",celsius_to_fahrenheit(temp)
elif choice == "f":
temp = input("Fahrenheit temperature:")
print "Celsius:",fahrenheit_to_celsius(temp)
elif choice != "q":
print_options()
choice = raw_input("option:")

執行範例:

> python temperature2.py
Options:
'p' print options
'c' convert from celsius
'f' convert from fahrenheit
'q' quit the program
option:c
Celsius temperature:30
Fahrenheit: 86.0
option:f
Fahrenheit temperature:60
Celsius: 15.5555555556
option:q

area2.py

#By Amos Satterlee
print
def hello():
print 'Hello!'

def area(width,height):
return width*height

def print_welcome(name):
print 'Welcome,',name

name = raw_input('Your Name: ')
hello(),
print_welcome(name)
print
print 'To find the area of a rectangle,'
print 'Enter the width and height below.'
print
w = input('Width: ')
while w <= 0:
print 'Must be a positive number'
w = input('Width: ')
h = input('Height: ')
while h <= 0:
print 'Must be a positive number'
h = input('Height: ')
print 'Width =',w,' Height =',h,' so Area =',area(w,h)

執行範例:

Your Name: Josh
Hello!
Welcome, Josh

To find the area of a rectangle,
Enter the width and height below.

Width: -4
Must be a positive number
Width: 4
Height: 3
Width = 4 Height = 3 so Area = 12

練習

重新編寫 area.py 在 3.2 完成的程式,為一個正方形、長方形及圓形 (3.14 * radius**2) 的面積做一個獨立的函式,這程式應該包括一個選單介面。



Lists

多於一個值的變數

您已看到一般的變數儲存單一的值,不過其他變數類型可以儲存多於一個值,最簡單的類型稱為 list,以下是使用中的  list 的範例:

which_one = input("What month (1-12)? ")
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July',\
'August', 'September', 'October', 'November', 'December']
if 1 <= which_one <= 12:
print "The month is",months[which_one - 1]

以下是一個輸出範例:

What month (1-12)? 3
The month is March

在本例中 months 是一個 list,monthsmonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July',\ 'August', 'September', 'October', 'November', 'December'] 來定義 (留意 \ 可以用作分割一長行)。[]以逗號 (``,'') 開始及結束 list,分開 list 項目。list 在 months 中使用[which_one - 1],一個 list 包含由零開始的項目,換句話說,您應該使用 months[0],為 list 給予一個數字,它會傳回儲存在該位置的值。

if 1 <= which_one <= 12: 句式只會當 which_one 在一之十二中間才會是真實的 (換句話說,如果您曾在代數看過,這就是您想要的)。

Lists 可以被視為一系統的盒子,例如由demolist = ['life',42, 'the universe', 6,'and',7] 建立的盒子會如下:

盒子號碼 0 1 2 3 4 5
demolist `life' 42 `the universe' 6 `and' 7

每個盒子都由其數字參照,因此 demolist[0] 句式會取得 'life'demolist[1] 會取得 42,如此類推,直至 demolist[5] 取得 7。 

lists 的更多功能

下一個範例只是用來顯示很多其他東西 lists 可以做的 (就這一次我不預期您會輸入它來嘗試,但您應該自己研究一下 lists,直 至感到沒有問題為止。) 範例如下:
demolist = ['life',42, 'the universe', 6,'and',7]
print 'demolist = ',demolist
demolist.append('everything')
print "after 'everything' was appended demolist is now:"
print demolist
print 'len(demolist) =', len(demolist)
print 'demolist.index(42) =',demolist.index(42)
print 'demolist[1] =', demolist[1]
#Next we will loop through the list
c = 0
while c < len(demolist):
print 'demolist[',c,']=',demolist[c]
c = c + 1
del demolist[2]
print "After 'the universe' was removed demolist is now:"
print demolist
if 'life' in demolist:
print "'life' was found in demolist"
else:
print "'life' was not found in demolist"
if 'amoeba' in demolist:
print "'amoeba' was found in demolist"
if 'amoeba' not in demolist:
print "'amoeba' was not found in demolist"
demolist.sort()
print 'The sorted demolist is ',demolist

輸出結果為:

demolist =  ['life', 42, 'the universe', 6, 'and', 7]
after 'everything' was appended demolist is now:
['life', 42, 'the universe', 6, 'and', 7, 'everything']
len(demolist) = 7
demolist.index(42) = 1
demolist[1] = 42
demolist[ 0 ]= life
demolist[ 1 ]= 42
demolist[ 2 ]= the universe
demolist[ 3 ]= 6
demolist[ 4 ]= and
demolist[ 5 ]= 7
demolist[ 6 ]= everything
After 'the universe' was removed demolist is now:
['life', 42, 6, 'and', 7, 'everything']
'life' was found in demolist
'amoeba' was not found in demolist
The sorted demolist is [6, 7, 42, 'and', 'everything', 'life']

這範例使用整套新的函式,留意您只能列印整套 list,接著 append 函式是用來新增項目至 list 的結尾,len 傳回 list中項目的數目。一個 list 中有效的 indexes (用在 [] 內的數字)由 0 至 len - 1index 函式會告訴您項目在 list 中的第一個位置,留意 demolist.index(42) 如何傳回 1,而當 demolist[1] 執行時會傳回 42。#Next we will loop through the list 一行只是編程員的一個備忘 (亦稱為評論)。Python 會忽略任何以 # 開始的行,接著的行是:

c = 0
while c < len(demolist):
print 'demolist[',c,']=',demolist[c]
c = c + 1
建立一個變數 c ,以 0 開始,並遞增直至到達 list 的最後 index,同時 print 句式會列印 list 的每個元素。

del 指令可用來移除 list 中特定的元素,下幾行會使用 in 操作符測試元素是否在 list 中 。

sort 函式會將 list 排序,如果您需要一個從小至大或順字母排序的 list,那是很有用的,留意這會將 list 重新排列。

總結 list 有以下的操作:

範例 解釋
list[2] 在 index 2 存取元素
list[2] = 3 設定index 2 的元素為 3
del list[2] 在 index 2 移除元素
len(list) 傳回 list 的長度
"value" in list 如果 "value" 是 list 中的元素就是真實的
"value" not in list 如果 "value" 不是 list 中的元素就是真實的
list.sort() 排列 list
list.index("value") 傳回 "value" 第一次出現的 index
list.append("value") 在 list 的結尾新增 "value" 元素

下一個範例會以更有用的方法使用這些功能:

menu_item = 0
list = []
while menu_item != 9:
print "--------------------"
print "1. Print the list"
print "2. Add a name to the list"
print "3. Remove a name from the list"
print "4. Change an item in the list"
print "9. Quit"
menu_item = input("Pick an item from the menu: ")
if menu_item == 1:
current = 0
if len(list) > 0:
while current < len(list):
print current,". ",list[current]
current = current + 1
else:
print "List is empty"
elif menu_item == 2:
name = raw_input("Type in a name to add: ")
list.append(name)
elif menu_item == 3:
del_name = raw_input("What name would you like to remove: ")
if del_name in list:
item_number = list.index(del_name)
del list[item_number]
#The code above only removes the first occurance of
# the name. The code below from Gerald removes all.
#while del_name in list:
# item_number = list.index(del_name)
# del list[item_number]
else:
print del_name," was not found"
elif menu_item == 4:
old_name = raw_input("What name would you like to change: ")
if old_name in list:
item_number = list.index(old_name)
new_name = raw_input("What is the new name: ")
list[item_number] = new_name
else:
print old_name," was not found"
print "Goodbye"

以下是輸出結果的一部分:

--------------------
1. Print the list
2. Add a name to the list
3. Remove a name from the list
4. Change an item in the list
9. Quit

Pick an item from the menu: 2
Type in a name to add: Jack

Pick an item from the menu: 2
Type in a name to add: Jill

Pick an item from the menu: 1
0 . Jack
1 . Jill

Pick an item from the menu: 3
What name would you like to remove: Jack

Pick an item from the menu: 4
What name would you like to change: Jill
What is the new name: Jill Peters

Pick an item from the menu: 1
0 . Jill Peters

Pick an item from the menu: 9
Goodbye

那是一個很長的程式,現在就看一看源程式碼,list = [] 一行會令變數 list 成為沒有項目的 list (或元素)。下一個重要的行是 while menu_item != 9:,這行會開始一個 loop,允許這程式的選單系統,下幾行會顯示一個選單,並決定執行程式哪部分。

該部分:

current = 0
if len(list) > 0:
while current < len(list):
print current,". ",list[current]
current = current + 1
else:
print "List is empty"
檢查 list 並列印每個名字,len(list_name) 會告訴您 list 有多少個項目,如果 len 傳回 0 ,list 就是空白的。

拉著幾行之後,list.append(name) 句式會出現,它會使用 append 函式新增項目至 list 的結尾。跳過另外兩行,留意本部分的源碼:

item_number = list.index(del_name)
del list[item_number]
這兒 index 函式是用來找出 index 值,在之後會用來移除項目。del list[item_number] 是用來移除 list 的元素。

下一部分:

old_name = raw_input("What name would you like to change: ")
if old_name in list:
item_number = list.index(old_name)
new_name = raw_input("What is the new name: ")
list[item_number] = new_name
else:
print old_name," was not found"
使用 index 找出 item_number,再將 new_name 放在 old_name

恭喜您,您已掌握了 lists,您現在已對該語言有足夠的認識,可以做任何電腦可做的計算了 (這在技術上稱為 Turing-Completness)。當然,仍然有很多功能可以令您的生括更容易。

範例

test.py

## This program runs a test of knowledge

true = 1
false = 0

# First get the test questions
# Later this will be modified to use file io.
def get_questions():
# notice how the data is stored as a list of lists
return [["What color is the daytime sky on a clear day?","blue"],\
["What is the answer to life, the universe and everything?","42"],\
["What is a three letter word for mouse trap?","cat"]]
# This will test a single question
# it takes a single question in
# it returns true if the user typed the correct answer, otherwise false
def check_question(question_and_answer):
#extract the question and the answer from the list
question = question_and_answer[0]
answer = question_and_answer[1]
# give the question to the user
given_answer = raw_input(question)
# compare the user's answer to the testers answer
if answer == given_answer:
print "Correct"
return true
else:
print "Incorrect, correct was:",answer
return false
# This will run through all the questions
def run_test(questions):
if len(questions) == 0:
print "No questions were given."
# the return exits the function
return
index = 0
right = 0
while index < len(questions):
#Check the question
if check_question(questions[index]):
right = right + 1
#go to the next question
index = index + 1
#notice the order of the computation, first multiply, then divide
print "You got ",right*100/len(questions),"% right out of",len(questions)

#now lets run the questions
run_test(get_questions())

輸出範例:

What color is the daytime sky on a clear day?green
Incorrect, correct was: blue
What is the answer to life, the universe and everything?42
Correct
What is a three letter word for mouse trap?cat
Correct
You got 66 % right out of 3

練習

擴充 test.py 程式,令它有進行測試、檢視問題及答案清單、離開選項的選單。此外亦加一個問題: 「一台真正先進的機器會發出甚麼聲音?」答案為 "ping"。


For Loops

以下是本章的打字練習:
onetoten = range(1,11)
for count in onetoten:
print count
輸出結果如下:
1
2
3
4
5
6
7
8
9
10
輸出結果十分相似,但程源碼很不同。第一行使用 range 函式,range 函式使用兩個參數如 this range(start,finish)。start 是所產生的第一個數字,finish 比上一個數字大一,留意這程式可以較短的方式做到:
for count in range(1,11):
print count
以下是一些例子,顯示 range 指令的功能:
>>> range(1,10)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(-32, -20)
[-32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21]
>>> range(5,21)
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
>>> range(21,5)
[]
下一行 for count in onetoten: 使用 for 控制結構,一個 for 控制結構像 list 中的 for 變數。list從第一個元素一直看到最後一個,由於 for 會經歷 list 的每個元素,它會將每個放入變數。這會容許在 for loop 執行的連續時間使用變數,以下是示範的另一個範例 (您不用輸入這個):
demolist = ['life',42, 'the universe', 6,'and',7,'everything']
for item in demolist:
print "The Current item is:",
print item
輸出結果是:
The Current item is: life
The Current item is: 42
The Current item is: the universe
The Current item is: 6
The Current item is: and
The Current item is: 7
The Current item is: everything
留意 for loop 如何經歷,並在 list 中的每個元素設定項目。 (留意程式如何做到,如果您不想 print 往下一行,在句式結尾新增一個逗號 (即是,如果您想在該行列印其他東西) ) 那麼, for 有甚麼好處呢? (嘆息) 第一個用途是經歷 list 中的所有元素,並為每一個做一點東西。以下是將所有元素加起來的快捷方法:
list = [2,4,6,8]
sum = 0
for num in list:
sum = sum + num
print "The sum is: ",sum
輸出結果只有:
The sum is:  20
或您可以編寫一個程式,找出 list 中的任何重複,就如這程式一樣:
list = [4, 5, 7, 8, 9, 1,0,7,10]
list.sort()
prev = list[0]
del list[0]
for item in list:
if prev == item:
print "Duplicate of ",prev," Found"
prev = item
而為了好的習慣:
Duplicate of  7  Found
好,那麼它如何運作呢?以下是特別的除錯版本,幫助您明白 (您無須輸入這些):
l = [4, 5, 7, 8, 9, 1,0,7,10]
print "l = [4, 5, 7, 8, 9, 1,0,7,10]","\tl:",l
l.sort()
print "l.sort()","\tl:",l
prev = l[0]
print "prev = l[0]","\tprev:",prev
del l[0]
print "del l[0]","\tl:",l
for item in l:
if prev == item:
print "Duplicate of ",prev," Found"
print "if prev == item:","\tprev:",prev,"\titem:",item
prev = item
print "prev = item","\t\tprev:",prev,"\titem:",item
輸出結果為:
l = [4, 5, 7, 8, 9, 1,0,7,10]   l: [4, 5, 7, 8, 9, 1, 0, 7, 10]
l.sort() l: [0, 1, 4, 5, 7, 7, 8, 9, 10]
prev = l[0] prev: 0
del l[0] l: [1, 4, 5, 7, 7, 8, 9, 10]
if prev == item: prev: 0 item: 1
prev = item prev: 1 item: 1
if prev == item: prev: 1 item: 4
prev = item prev: 4 item: 4
if prev == item: prev: 4 item: 5
prev = item prev: 5 item: 5
if prev == item: prev: 5 item: 7
prev = item prev: 7 item: 7
Duplicate of 7 Found
if prev == item: prev: 7 item: 7
prev = item prev: 7 item: 7
if prev == item: prev: 7 item: 8
prev = item prev: 8 item: 8
if prev == item: prev: 8 item: 9
prev = item prev: 9 item: 9
if prev == item: prev: 9 item: 10
prev = item prev: 10 item: 10
我將那麼多 print 句式放在源碼的原因是,讓您可以看到每一行在做甚麼。 (順帶一提,如果您不能找出程式不運作的原因,嘗試加入很多 print 句式,您會看到有甚麼發生) 首先程式以一個沉悶的舊清單開始,然後程式會排列清單,那麼任何重複都會放入去。然後程式會啟用之前的變數,接著清單的第一個元素會被刪除,因此第一個項目不會錯誤地視為重複的。接著會進入一個 for loop,清單每一個項目都會被選取,查看是否與之前的一樣。如果找到重複的,prev 會更改,那麼下一次執行 for loop 時,prev 就是現有項目之前的項目。不出所料,7 就會是重複的。(留意如何使用 \t 列印 tab。)

另一種使用 for loops 方法是做一些東西數次,以下是一些源碼,列印 Fibonacci 系統的首 11 個數字:

a = 1
b = 1
for c in range(1,10):
print a,
n = a + b
a = b
b = n
出人意表的結果是:
1 1 2 3 5 8 13 21 34
所有可以 for loops 完成的東西亦可以 while loops 完成,但 for loops 會更容易經歷清單中的所有元素,或做一些東西數次。

Boolean Expressions

以下是 boolean expressions 的一個小範例 (您無須輸入這些):
a = 6
b = 7
c = 42
print 1, a == 6
print 2, a == 7
print 3,a == 6 and b == 7
print 4,a == 7 and b == 7
print 5,not a == 7 and b == 7
print 6,a == 7 or b == 7
print 7,a == 7 or b == 6
print 8,not (a == 7 and b == 6)
print 9,not a == 7 and b == 6
輸出結果如下:
1 1
2 0
3 1
4 0
5 1
6 1
7 0
8 1
9 0
發生甚麼呢?程式包含了很多有趣好看的 print 句式,每個 print 句式會列印一個數字及一個表達式,數字是用來協助追縱我所處理的句式,留意每個表達式如何最終變成 0 或 1,在 Python,false 會寫入為 0,true 會寫入為 1,如下:
print 1, a == 6
print 2, a == 7
這會如預期分別列印一個 1 及一個 0,因為第一個是 true 而第二個是 false。第三個 print,print 3,a == 6 and b == 7 是有一點不同。如果之前的兩個句式及之後的句式是 true,整個表達式都是 true,否則整個表達式都是 false。下一行 print 4,a == 7 and b == 7 顯示如果 and 表達式部分為 false,整個表達式都會是 false。 and 的行為可以總結如下:

表達式 結果
true and true true
true and false false
false and true false
false and false false

留意如果第一個表達式為 false,Python 不會檢查第二個表達式,因為它知道整個表達式都會是 false。

下一行,print 5,not a == 7 and b == 7 使用 not 操作符, not 只會給予表達式的相反 (表達式可以重寫為 print 5,a != 7 and b == 7),如下表:

表達式 結果
not true false
not false true

接著的兩行,print 6,a == 7 or b == 7 print 7,a == 7 or b == 6 使用 or 操作符。如果第一個表達式為 true,或第二個表達式為 true 或兩者都是 true,or 操作符會傳回 true。如果兩者都不是 true,它會傳回 false,如下表:

表達式 結果
true or true true
true or false true
false or true true
false or false false

留意如果第一個表達式是 true,Python 不會檢查第二個表達式,因為它知道整個表達式都是 true。如果至少表達式的一半為 true,or 就是 true,這就能運作。第一部分是 true,因此第二部分可以是 false 或 true,但整個表達式仍然是 true 的。

接著兩行 print 8,not (a == 7 and b == 6) print 9,not a == 7 and b == 6 顯示括弧可以用來將表達式群組,並迫使一部分首先評估。留意括弧會將表達式從 false 改為 true,這是因為括弧強使 not 套用至整個表達式,而不是單單 a == 7 那部分。

以下是使用 boolean expression 的範例:

list = ["Life","The Universe","Everything","Jack","Jill","Life","Jill"]

#make a copy of the list. See the More on Lists chapter to explain what
#[:] means.
copy = list[:]
#sort the copy
copy.sort()
prev = copy[0]
del copy[0]

count = 0

#go through the list searching for a match
while count < len(copy) and copy[count] != prev:
prev = copy[count]
count = count + 1

#If a match was not found then count can't be < len
#since the while loop continues while count is < len
#and no match is found
if count < len(copy):
print "First Match: ",prev

輸出結果如下:

First Match:  Jill

這個程式會透過繼續檢查符合 while count < len(copy and copy[count] 這句式而運作,當其中一個 count大於複本最後的 index,或找到符合的句式時,它不會再是 true,因此 loop 會離開。if 只是檢查確定 while 會因找到符合的句式而離開。

另一個 and 的「技巧」會在本例中使用,假如您查看列表,並留意到第三個記錄是 ``false and won't check''。如果 count >= len(copy) (換句話說 count < len(copy)為 false),那麼 copy[count] 就永不會被檢查。這是因為 Python 知道如果第一個為 false,那麼兩者都不能為 true。這稱為短路,如果 and 的第二部會導致錯誤或有東西出錯,這是很有用的。我使用第 一個表達式 count < len(copy)) count 是 copy 的一個有效的index 。(如果您不相信我而移除 `Jill' 及 `Life',檢查它仍能運作,再逆轉 count < len(copy) 及 copy[count] != prev to copy[count] != prev and count < len(copy)的次序)。

當您需要同時檢查兩個或更多東西時,就可以使用 Boolean expressions。

範例

password1.py

## This programs asks a user for a name and a password.
# It then checks them to make sure the the user is allowed in.

name = raw_input("What is your name? ")
password = raw_input("What is the password? ")
if name == "Josh" and password == "Friday":
print "Welcome Josh"
elif name == "Fred" and password == "Rock":
print "Welcome Fred"
else:
print "I don't know you."

執行範例

What is your name? Josh
What is the password? Friday
Welcome Josh

What is your name? Bill
What is the password? Money
I don't know you.

練習

編寫程式,讓使用者猜您的名字,但在程式結束前他們只有三次機會。


字典

本章是有關字典的,字典有鍵及值,鍵是用來找出值的,以下是使用中的字典範例:
def print_menu():
print '1. Print Phone Numbers'
print '2. Add a Phone Number'
print '3. Remove a Phone Number'
print '4. Lookup a Phone Number'
print '5. Quit'
print
numbers = {}
menu_choice = 0
print_menu()
while menu_choice != 5:
menu_choice = input("Type in a number (1-5):")
if menu_choice == 1:
print "Telephone Numbers:"
for x in numbers.keys():
print "Name: ",x," \tNumber: ",numbers[x]
print
elif menu_choice == 2:
print "Add Name and Number"
name = raw_input("Name:")
phone = raw_input("Number:")
numbers[name] = phone
elif menu_choice == 3:
print "Remove Name and Number"
name = raw_input("Name:")
if numbers.has_key(name):
del numbers[name]
else:
print name," was not found"
elif menu_choice == 4:
print "Lookup Number"
name = raw_input("Name:")
if numbers.has_key(name):
print "The number is",numbers[name]
else:
print name," was not found"
elif menu_choice != 5:
print_menu()
以下是我的輸出結果:
1. Print Phone Numbers
2. Add a Phone Number
3. Remove a Phone Number
4. Lookup a Phone Number
5. Quit

Type in a number (1-5):2
Add Name and Number
Name:Joe
Number:545-4464
Type in a number (1-5):2
Add Name and Number
Name:Jill
Number:979-4654
Type in a number (1-5):2
Add Name and Number
Name:Fred
Number:132-9874
Type in a number (1-5):1
Telephone Numbers:
Name: Jill Number: 979-4654
Name: Joe Number: 545-4464
Name: Fred Number: 132-9874

Type in a number (1-5):4
Lookup Number
Name:Joe
The number is 545-4464
Type in a number (1-5):3
Remove Name and Number
Name:Fred
Type in a number (1-5):1
Telephone Numbers:
Name: Jill Number: 979-4654
Name: Joe Number: 545-4464

Type in a number (1-5):5
這程式與本章較早前的 name list 相似,以下是程式如何運作,首先 function print_menu 會被定義, print_menu 只列印一個選單供程式之後使用兩之,接著是有趣的 line numbers = {},該行所做的就是告訴 Python,numbers 是一個字典,接著的幾行只是令選單運作,那幾行如下:
for x in numbers.keys():
print "Name: ",x," \tNumber: ",numbers[x]
檢查字典並列印所有資訊,numbers.keys() 函式會傳回一個清單,之後由for loop使用,由 keys 傳回的清單不是在任何特定的次序,因此如果您想它順字母次序,必須先排序。與清單相似,numbers[x] 句式用來存取字典中特定的成員,當然在這情況下 x 是一個字串。接著一行 numbers[name] = phone 為字典新增一個名字及電話號碼。假如名字已在字典中, phone 會取代之前的資料,接著幾行如下:
if numbers.has_key(name):
del numbers[name]
查看名字是否在字典中,如果是就移除它。如果名字是數字,numbers.has_key(name) 函式會傳回 true,否則會傳回false。 del numbers[name] 一行會移除 key 的名稱及相關的值,該數行如下:
if numbers.has_key(name):
print "The number is",numbers[name]
查看字典是否有特定的 key ,如果有就列印與它相關的數字。最後如果選單選項無效,它會重新列印選單供您查看:

重溫: 字典有鍵及值,鍵可以是字串或數字,鍵指向值,值可以是變數的任何類型 (包括清單或甚至字典 (那些字典或清單當然會包括字典或清單本身 (可怕吧? :) ))。以下是在字典中使用清單的範例:

max_points = [25,25,50,25,100]
assignments = ['hw ch 1','hw ch 2','quiz ','hw ch 3','test']
students = {'#Max':max_points}

def print_menu():
print "1. Add student"
print "2. Remove student"
print "3. Print grades"
print "4. Record grade"
print "5. Print Menu"
print "6. Exit"
def print_all_grades():
print '\t',
for i in range(len(assignments)):
print assignments[i],'\t',
print
keys = students.keys()
keys.sort()
for x in keys:
print x,'\t',
grades = students[x]
print_grades(grades)
def print_grades(grades):
for i in range(len(grades)):
print grades[i],'\t\t',
print
    
print_menu()
menu_choice = 0
while menu_choice != 6:
print
menu_choice = input("Menu Choice (1-6):")
if menu_choice == 1:
name = raw_input("Student to add:")
students[name] = [0]*len(max_points)
elif menu_choice == 2:
name = raw_input("Student to remove:")
if students.has_key(name):
del students[name]
else:
print "Student: ",name," not found"
elif menu_choice == 3:
print_all_grades()

elif menu_choice == 4:
print "Record Grade"
name = raw_input("Student:")
if students.has_key(name):
grades = students[name]
print "Type in the number of the grade to record"
print "Type a 0 (zero) to exit"
for i in range(len(assignments)):
print i+1,' ',assignments[i],'\t',
print
print_grades(grades)
which = 1234
while which != -1:
which = input("Change which Grade:")
which = which-1
if 0 <= which < len(grades):
grade = input("Grade:")
grades[which] = grade
elif which != -1:
print "Invalid Grade Number"
else:
print "Student not found"
elif menu_choice != 6:
print_menu()
以下是輸出範例:
1. Add student
2. Remove student
3. Print grades
4. Record grade
5. Print Menu
6. Exit

Menu Choice (1-6):3
hw ch 1 hw ch 2 quiz hw ch 3 test
#Max 25 25 50 25 100
Menu Choice (1-6):6
1. Add student
2. Remove student
3. Print grades
4. Record grade
5. Print Menu
6. Exit

Menu Choice (1-6):1
Student to add:Bill
Menu Choice (1-6):4
Record Grade
Student:Bill
Type in the number of the grade to record
Type a 0 (zero) to exit
1 hw ch 1 2 hw ch 2 3 quiz 4 hw ch 3 5 test
0 0 0 0 0
Change which Grade:1
Grade:25
Change which Grade:2
Grade:24
Change which Grade:3
Grade:45
Change which Grade:4
Grade:23
Change which Grade:5
Grade:95
Change which Grade:0
Menu Choice (1-6):3  
hw ch 1 hw ch 2 quiz hw ch 3 test
#Max 25 25 50 25 100
Bill 25 24 45 23 95

Menu Choice (1-6):6
以下是程式運作的方式,基本上 students 變數是一個字典,以學生的名字為鍵﹐他們的成績為值。首二行只是建立兩個清單,下一行 students = {'#Max':max_points} 建立一個新的字典,以 #Max 為鍵,值設定為  [25,25,50,25,100] (因為在建立 assignments 後,那就是 max_points ) (我使用的 #Max since # 鍵已排序在任何字母字元之首)。 接著定義 print_menu,接著 print_all_grades 函式在以下幾行中定義:
def print_all_grades():
print '\t',
for i in range(len(assignments)):
print assignments[i],'\t',
print
keys = students.keys()
keys.sort()
for x in keys:
print x,'\t',
grades = students[x]
print_grades(grades)
留意鍵如何首先從 students 字典中取得,而 keys 函式在 keys = students.keys()一行, keys 是一個清單,因此該清單所有函式都可以使用。接著鍵會在 keys.sort() 一行排序,因為它是一個清單。 for 用來經歷所有鍵,分數儲存在字典的清單中,因此 assignment grades = students[x] 給予 grades儲存在 x 鍵的清單,print_grades 函式只會列印一個清單,而且在其後定義幾行。

程式之後幾行會落實選單不同的選項,students[name] = [0]*len(max_points) 一行為學生的名字鍵新增一個學生, [0]*len(max_points) 記號只是建立 0 的陣列,那是與 max_points 清單的長度一樣。

移除學生記錄只是刪除一個學,與電話簿範例相似。記錄分數選項更複雜一點,分數會從 grades = students[name]一行提取,取得學生名稱的分數的參照。分數其後會記錄在 grades[which] = grade 一行中,您可能會留意到分數永不會放在 students 字典中 (就如在 no students[name] = grades)。遺漏了句子的原因是分數其實是 students[name] 的另一個名稱,因此更改 grades 會更改 student[name]

字典為連結鍵及值提供一種很容易的方式,這可以很容易追縱連結不同鍵的資料。


使用模組

以下是本章的打字練習 (將它名為 cal.py):
import calendar

year = input("Type in the year number:")
calendar.prcal(year)
以下是輸出結果的一部分:
Type in the year number:2001
2001

January February March
Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7 1 2 3 4 1 2 3 4
8 9 10 11 12 13 14 5 6 7 8 9 10 11 5 6 7 8 9 10 11
15 16 17 18 19 20 21 12 13 14 15 16 17 18 12 13 14 15 16 17 18
22 23 24 25 26 27 28 19 20 21 22 23 24 25 19 20 21 22 23 24 25
29 30 31 26 27 28 26 27 28 29 30 31
(我略過部分輸出結果,但我想您已知道意思) 那麼程式會做些甚麼?第一行 import calendar 使用新的指令 importimport 指令會載入一個模組 (在本例中是 calendar 模組)。要查看標準模組中的可用指令,可看看 python 的程式庫參照 (如果您下載了它) 或往 http://www.python.org/doc/current/lib/lib.html 。 calendar 模組在 5.9 描述,如果您查看文檔,會有一個叫 prcal 的函式,列印一年的月曆。calendar.prcal(year) 一行使用該函式,總括而言是使用一個import 模組,然後在模組中使用 module_name.function。另一種方法是編寫程式:
from calendar import prcal

year = input("Type in the year number:")
prcal(year)
這個版本會從模組輸入一個特定的函式,以下是另一個使用 Python Library 的程式 (將它名為類似 clock.py) (同時按 Ctrl 及 'c' 鍵可殺掉程式):
from time import time, ctime

prev_time = ""
while(1):
the_time = ctime(time())
if(prev_time != the_time):
print "The time is:",ctime(time())
prev_time = the_time
輸出結果為:
The time is: Sun Aug 20 13:40:04 2000
The time is: Sun Aug 20 13:40:05 2000
The time is: Sun Aug 20 13:40:06 2000
The time is: Sun Aug 20 13:40:07 2000
Traceback (innermost last):
File "clock.py", line 5, in ?
the_time = ctime(time())
KeyboardInterrupt
輸出當然是無盡的,因此我取消了它 (否則輸出結果會繼續,直至按 Ctrl+C 為止)。程式只會做一個無限的 loop ,而每次會作檢查,如果時間有變就會列印出來。留意 import 句式後多個名稱會在 from time import time, ctime 一行使用。 

Python Library 包含很多有用的函式,這些函式會讓您的程式有更多功能,而它們很多會簡化 Python 編程。

練習 

重寫 5.2 部分的 high_low.py  程式,使用那時間的最後兩個數字為 'random' 數字。


更多有關 Lists

我們已看過 lists 以及如何使用它們,現在您已有更多背景知識,我們會更深入探討有關 lists。首先我們會查看更多取得 list 中元素的方法,然後我們會談談有關複製它們。

以下是使用 indexing 存取 list 中的單一元素:

>>> list = ['zero','one','two','three','four','five']   
>>> list[0]
'zero'
>>> list[4]
'four'
>>> list[5]
'five'
所有那些範例您應該似曾相識,如果您想list 中的第一個項目只查看 index 0,第二個項目是 index 1 ﹐如此類推。不過如果您想要列表中的最後項目又如何?一種方式是使用 len 函式如 list[len(list)-1] 。這種方式可以運作,因為 len 函式通常會傳回最後一個 index 加一,最後第二個會是 list[len(list)-2]。有更容易的方法做到,在 Python 中最後一個項目通常是 index -1,最後第二個是 index -2,如此類推,以下是更多範例:
>>> list[len(list)-1]  
'five'
>>> list[len(list)-2]
'four'
>>> list[-1]
'five'
>>> list[-2]
'four'
>>> list[-6]
'zero'
結果 list 中的任何項目可以兩種方式做索引:由前面至後面。

另一種有用的方式是令 lists 的一部分使用 slices,以下是另一個範例,令您知道它有甚麼用途:

>>> list = [0,'Fred',2,'S.P.A.M.','Stocking',42,"Jack","Jill"]
>>> list[0]
0
>>> list[7]
'Jill'
>>> list[0:8]
[0, 'Fred', 2, 'S.P.A.M.', 'Stocking', 42, 'Jack', 'Jill']
>>> list[2:4]
[2, 'S.P.A.M.']
>>> list[4:7]
['Stocking', 42, 'Jack']
>>> list[1:5]
['Fred', 2, 'S.P.A.M.', 'Stocking']
Slices 是用來傳回一個 list 的部分,slice operator 是以 list[first_index:following_index]形式。 slice 從 first_indexfollowing_index 前的 index。您可以使用兩種 indexing:
>>> list[-4:-2]
['Stocking', 42]
>>> list[-4]
'Stocking'
>>> list[-4:6]
['Stocking', 42]
另一個 slices 的技巧是未指明的 index,如果第一個 index 未有指明,會假設是清單的開始。如果隨後的 index 未有指明,會假設是清單的所有餘下部分。以下是一些範例:
>>> list[:2]
[0, 'Fred']
>>> list[-2:]
['Jack', 'Jill']
>>> list[:3]
[0, 'Fred', 2]
>>> list[:-5]
[0, 'Fred', 2]
以下是一個程式範例 (如果您想的話,可在詩的定義上複製及貼上):
poem = ["<B>","Jack","and","Jill","</B>","went","up","the","hill","to","<B>",\
"fetch","a","pail","of","</B>","water.","Jack","fell","<B>","down","and",\
"broke","</B>","his","crown","and","<B>","Jill","came","</B>","tumbling",\
"after"]

def get_bolds(list):
true = 1
false = 0
## is_bold tells whether or not the we are currently looking at
## a bold section of text.
is_bold = false
## start_block is the index of the start of either an unbolded
## segment of text or a bolded segment.
start_block = 0
for index in range(len(list)):
##Handle a starting of bold text
if list[index] == "<B>":
if is_bold:
print "Error: Extra Bold"
##print "Not Bold:",list[start_block:index]
is_bold = true
start_block = index+1
##Handle end of bold text
##Remember that the last number in a slice is the index
## after the last index used.
if list[index] == "</B>":
if not is_bold:
print "Error: Extra Close Bold"
print "Bold [",start_block,":",index,"] ",\
list[start_block:index]
is_bold = false
start_block = index+1

get_bolds(poem)
輸出結果如下:
Bold [ 1 : 4 ]  ['Jack', 'and', 'Jill']
Bold [ 11 : 15 ] ['fetch', 'a', 'pail', 'of']
Bold [ 20 : 23 ] ['down', 'and', 'broke']
Bold [ 28 : 30 ] ['Jill', 'came']

get_bold 函式會取得清單,分割為字及標記。它尋找的標記為 <B> ,會開始粗體文字,而 <\B> 會結束粗體文字。get_bold 函式會搜尋開始及結束標記。

lists 的下一項特點是複製它們,如果您嘗試一些簡單的東西如:

>>> a = [1,2,3]
>>> b = a
>>> print b
[1, 2, 3]
>>> b[1] = 10
>>> print b
[1, 10, 3]
>>> print a
[1, 10, 3]
這可能會有點出人意表,因為修改 a 亦會令 b 有改變,導致 b = a 句式令 b 成為 a 的參照。這表示 b 可以被認為是 a 的另一個名稱。結果 b 的任何改變亦會令 a 有所改變。不過有些任務卻不會為一個清單建立兩個名稱:
>>> a = [1,2,3]
>>> b = a*2
>>> print a
[1, 2, 3]
>>> print b
[1, 2, 3, 1, 2, 3]
>>> a[1] = 10
>>> print a
[1, 10, 3]
>>> print b
[1, 2, 3, 1, 2, 3]

在這個情況下,b 不是 a  的一個參照,因為 a*2 表達式會建立一個新的 list。然後 b = a*2 句式會令 b 成為 a*2 的參照,而不是 a 的參照。 所有任務操作會建立一個參照,當您傳回一個 list 成為函式的參數時,您亦建立一個參照。很多時也無須擔憂有關建立參照多於複製。不過當您需要修改一個 list,而無須更改list 的另一個名稱,您需要確定您實際建立了一個複本。

我們有幾個方法可以建立 list 的複本,最簡單的是在大部分時間下可以運作,就是 slice operator,因為即使它是整個 list 的一部分,它通常會建立一個新的list:

>>> a = [1,2,3]
>>> b = a[:]
>>> b[1] = 10
>>> print a
[1, 2, 3]
>>> print b
[1, 10, 3]

slice [:] 會建立 list 的新複本,不過它只會複製最外層的 list。當中任何 sublist 仍然是原有list的  sublist 的參照。因此如 list 中包含 lists,內層的 lists 亦要複製。您可以人手做,但 Python 已包含一個模組可以做。您可以使用 copy 模組的 deepcopy 函式:

>>> import copy
>>> a = [[1,2,3],[4,5,6]]
>>> b = a[:]
>>> c = copy.deepcopy(a)
>>> b[0][1] = 10
>>> c[1][1] = 12
>>> print a
[[1, 10, 3], [4, 5, 6]]
>>> print b
[[1, 10, 3], [4, 5, 6]]
>>> print c
[[1, 2, 3], [4, 12, 6]]
首先留意 a 是陣列中的一個陣列,接著要留意當 b[0][1] = 10 執行時, ab 都會被改變﹐但 c 不會。這是因為當使用 slice operator 時,內層的陣列仍然是參照。不過 deepcopy c 會全面複製。

因此,我應該在每次使用函式或 = 時,擔憂有關參照的問題嗎?一個好消息是您只須在使用字典及 lists 時才擔憂有關參照的問題。當指派數字及字串時會建立參照,但修改它們的數字上的操作會建立新的複本,因此您永不能意外地修改它們。當您在修改list或字典時,要想一想有關參照的問題。

現在您可能好奇為甚麼要使用參照?基本的理由是速度,為一千個元素清單建立參照是會比複製所有元素更快。另一個原因是它允許您有函式修改輸入的清單或字典,如果您曾經在不應更改的資料上,資料被修改了這些奇怪的問題,只需記著有關參照。


有關字串

而現在會展示字串可以做到的出色技巧:

def shout(string):
for character in string:
print "Gimme a "+character
print "'"+character+"'"

shout("Lose")

def middle(string):
print "The middle character is:",string[len(string)/2]

middle("abcdefg")
middle("The Python Programming Language")
middle("Atlanta")

輸出結果如下:

Gimme a L
'L'
Gimme a o
'o'
Gimme a s
's'
Gimme a e
'e'
The middle character is: d
The middle character is: r
The middle character is: a
這些程式示範的就是字串在幾種方式下與 lists 相似,shout 程序顯示的 for loops 可以與字串一同使用,就像能與 lists 使用一樣。中間的程序顯示字串亦能使用len 函式、陣列索引及 slices,大部分 list 功能亦可以在字串上運作。

下一項功能顯示一些字串特定的功能:

def to_upper(string):
## Converts a string to upper case
upper_case = ""
for character in string:
if 'a' <= character <= 'z':
location = ord(character) - ord('a')
new_ascii = location + ord('A')
character = chr(new_ascii)
upper_case = upper_case + character
return upper_case

print to_upper("This is Text")
輸出結果為:
THIS IS TEXT
這是可以運作的,因為電腦代表字串中的字元,作為由 0 至 255 的數字。Python 有的函式稱為 ord (ordinal 的縮寫),會將字元傳回為一個數字。此外亦有一個相應的函式稱為 chr,將數字轉換為字元。有了這個概代後,程式應該開始清晰。第一個詳情是 if 'a' <= character <= 'z': 一行,會查看字母是否小寫。假如是小寫,就會使用下一行。首先它會轉換至一個位置,因此 a=0,b=1,c=2 ,如此類推,還有這行:location = ord(character) - ord('a')。接著新的值以 new_ascii = location + ord('A')找到,這個值會轉換為一個現在是大寫的字元。

現在做一些互動的打字練習:

>>> #Integer to String
...
>>> 2
2
>>> repr(2)
'2'
>>> -123
-123
>>> repr(-123)
'-123'
>>> #String to Integer
...
>>> "23"
'23'
>>> int("23")
23
>>> "23"*2
'2323'
>>> int("23")*2
46
>>> #Float to String
...
>>> 1.23
1.23
>>> repr(1.23)
'1.23'
>>> #Float to Integer
...
>>> 1.23
1.23
>>> int(1.23)
1
>>> int(-1.23)
-1
>>> #String to Float
...
>>> float("1.23")
1.23
>>> "1.23"
'1.23'
>>> float("123")
123.0

如果您未估計,repr 函式會將整數轉換為字串,而 int 函式可以將字串轉換為整數。 float 函式可以將整數轉換為浮點數。repr 函式傳回一個可列印的展示。以下是其中一些範例:

>>> repr(1)
'1'
>>> repr(234.14)
'234.14'
>>> repr([4,42,10])
'[4, 42, 10]'
int 函式嘗試將字串 (或浮點數) 轉換為整數,此外亦有類似的函式稱為 float ,將整數或字串轉換為浮點數。Python 有的另一個函式是 eval 函式,eval 函式會得出一個字串,並傳回 python 認為它找到的資料類型。例如:
>>> v=eval('123')
>>> print v,type(v)
123 <type 'int'>
>>> v=eval('645.123')
>>> print v,type(v)
645.123 <type 'float'>
>>> v=eval('[1,2,3]')
>>> print v,type(v)
[1, 2, 3] <type 'list'>
如果您使用 eval 函式,您應該查看它是否傳回您預期的類型。

一個有用的字串函式是 split 函式,範例如下:

>>> import string
>>> string.split("This is a bunch of words")
['This', 'is', 'a', 'bunch', 'of', 'words']
>>> string.split("First batch, second batch, third, fourth",",")
['First batch', ' second batch', ' third', ' fourth']
留意 split 如何將字串轉換為一列字串,字串預設由空間分割,或可選的第二個參數 (在本例中為逗號)。

範例

#This program requires a excellent understanding of decimal numbers
def to_string(in_int):
"Converts an integer to a string"
out_str = ""
prefix = ""
if in_int < 0:
prefix = "-"
in_int = -in_int
while in_int / 10 != 0:
out_str = chr(ord('0')+in_int % 10) + out_str
in_int = in_int / 10
out_str = chr(ord('0')+in_int % 10) + out_str
return prefix + out_str

def to_int(in_str):
"Converts a string to an integer"
out_num = 0
if in_str[0] == "-":
multiplier = -1
in_str = in_str[1:]
else:
multiplier = 1
for x in range(0,len(in_str)):
out_num = out_num * 10 + ord(in_str[x]) - ord('0')
return out_num * multiplier

print to_string(2)
print to_string(23445)
print to_string(-23445)
print to_int("14234")
print to_int("12345")
print to_int("-3512")

輸出結果如下:

2
23445
-23445
14234
12345
-3512

檔案 IO

以下是 file IO 的一個簡單例子:#Write a file out_file = open("test.txt","w") out_file.write("This Text is going to out file\nLook at it and see\n") out_file.close() #Read a file in_file = open("test.txt","r") text = in_file.read() in_file.close() print text,  test.txt 的輸出結果及內容為:This Text is going to out file Look at it and see。留意它會在您執行程式的目錄中寫入一個名為 test.txt 的檔案,字串中的 \n 會告訴 Python 開新一行。

檔案 IO 的概念是:

  1. open 函式取得一個檔案物件。
  2. 讀取或寫入檔案物件 (視乎它如何開啟)
  3. 關閉它

第一個步驟是取得一個檔案物件,所做的方法是使用 open 函式,格式為 file_object = open(filename,mode) ,而 file_object 是儲存檔案物件的變數,filename 是一個字串﹐有檔案名稱,而模式 "r" 是讀取檔案或 "w" 寫入檔案。接著可以呼叫檔案物件函式。兩個最普遍的函式是讀取及寫入, write 函式新增字串在檔案的最後,read 函式讀取檔案下一項東西,並將它傳回為字串。如果沒有給予參數,它會傳回整個檔案 (就如範例中所完成的)。

現在以下是我們之前製作的電話號碼程式的新版本:

import string true = 1 false = 0 def print_numbers(numbers): print "Telephone Numbers:" for x in numbers.keys(): print "Name: ",x," \tNumber: ",numbers[x] print def add_number(numbers,name,number): numbers[name] = number def lookup_number(numbers,name): if numbers.has_key(name): return "The number is "+numbers[name] else: return name+" was not found" def remove_number(numbers,name): if numbers.has_key(name): del numbers[name] else: print name," was not found" def load_numbers(numbers,filename): in_file = open(filename,"r") while true: in_line = in_file.readline() if in_line == "": break in_line = in_line[:-1] [name,number] = string.split(in_line,",") numbers[name] = number in_file.close() def save_numbers(numbers,filename): out_file = open(filename,"w") for x in numbers.keys(): out_file.write(x+","+numbers[x]+"\n") out_file.close() def print_menu(): print '1. Print Phone Numbers' print '2. Add a Phone Number' print '3. Remove a Phone Number' print '4. Lookup a Phone Number' print '5. Load numbers' print '6. Save numbers' print '7. Quit' print phone_list = {} menu_choice = 0 print_menu() while menu_choice != 7: menu_choice = input("Type in a number (1-7):") if menu_choice == 1: print_numbers(phone_list) elif menu_choice == 2: print "Add Name and Number" name = raw_input("Name:") phone = raw_input("Number:") add_number(phone_list,name,phone) elif menu_choice == 3: print "Remove Name and Number" name = raw_input("Name:") remove_number(phone_list,name) elif menu_choice == 4: print "Lookup Number" name = raw_input("Name:") print lookup_number(phone_list,name) elif menu_choice == 5: filename = raw_input("Filename to load:") load_numbers(phone_list,filename) elif menu_choice == 6: filename = raw_input("Filename to save:") save_numbers(phone_list,filename) elif menu_choice == 7: pass else: print_menu() print "Goodbye" Notice that it now includes saving and loading files. Here is some output of my running it twice: > python tele2.py 1. Print Phone Numbers 2. Add a Phone Number 3. Remove a Phone Number 4. Lookup a Phone Number 5. Load numbers 6. Save numbers 7. Quit Type in a number (1-7):2 Add Name and Number Name:Jill Number:1234 Type in a number (1-7):2 Add Name and Number Name:Fred Number:4321 Type in a number (1-7):1 Telephone Numbers: Name: Jill Number: 1234 Name: Fred Number: 4321 Type in a number (1-7):6 Filename to save:numbers.txt Type in a number (1-7):7 Goodbye > python tele2.py 1. Print Phone Numbers 2. Add a Phone Number 3. Remove a Phone Number 4. Lookup a Phone Number 5. Load numbers 6. Save numbers 7. Quit Type in a number (1-7):5 Filename to load:numbers.txt Type in a number (1-7):1 Telephone Numbers: Name: Jill Number: 1234 Name: Fred Number: 4321 Type in a number (1-7):7 Goodbye

這個程式的新部分是:

def load_numbers(numbers,filename): in_file = open(filename,"r") while 1: in_line = in_file.readline() if len(in_line) == 0: break in_line = in_line[:-1] [name,number] = string.split(in_line,",") numbers[name] = number in_file.close() def save_numbers(numbers,filename): out_file = open(filename,"w") for x in numbers.keys(): out_file.write(x+","+numbers[x]+"\n") out_file.close()

首先我們會查看程式的 save 部分,它先以 open(filename, "w") 指令建立一個檔案物件,接著它會以 out_file.write(x+","+numbers[x]+"\n") 指令為每個電話號碼經過並建立一行,這會寫入一行,包含名稱、一個逗號、數字及新一行。

載入的部分有點複雜,它會透過取得一個檔案物件開始,然後它會使用 while 1: loop 保持 looping ,直至遇到 break 句式,接著它會得出 in_line = in_file.readline()一行,當遇到檔案結尾時, readline 函式會傳回一個空白的字串 (len(string) == 0)。if 句式會查看這個,而當這種情況發生時,會中斷 while loop。當然,如果 readline 函式未在該行結尾傳回新一行,沒有方式辨別空白字串是空白行或檔案的結尾,因此在傳回 readline 時會保留新一行。因此我們要取消新一行, in_line = in_line[:-1] 一行會透過放棄最後一個字元為我們做到,接著一行 [name,number] = string.split(in_line,",") 會在逗號分割該行為一個名稱及一個數字,然後會加入數字字典。

練習

現在修改第 11 部分的分數程式,令它使用檔案 IO 保留學生的記錄。


處理未完整的程式 (或如何處理錯誤)

因此您現在有完整的程式,它會完美無誤地執行,除非有一項事情會令它在無效的使用者輸入時崩潰。不用害怕,因為 Python 有特別的控制結構,稱為 try,並會嘗試做一些事情。以下是有問題的程式範例:

print "Type Control C or -1 to exit" number = 1 while number != -1: number = int(raw_input("Enter a number: ")) print "You entered: ",number

留意當您輸入 @#& 時,它如何輸出一些東西:

Traceback (innermost last): File "try_less.py", line 4, in ? number = int(raw_input("Enter a number: ")) ValueError: invalid literal for int(): @#&

您看到 int 函式不太高興 @#& 數字 (它應該是),最後一行會顯示問題所在;Python 找到一個 ValueError,我們的程式會如何處理?我們首先要做的是:將錯誤出現的地方放在 try block 內,第二:告訴 Python 我們想 ValueError s 如何處理,以下的程式會做到:

print "Type Control C or -1 to exit" number = 1 while number != -1: try: number = int(raw_input("Enter a number: ")) print "You entered: ",number except ValueError: print "That was not a number."

現在當我們執行新程式時,會得出 @#& ,它會告訴我們 ``That was not a number.'' 並繼續它之前所做的。

當程式仍然有一些錯誤時,您會知道如何處理,將源碼放在 try block,並在 except  block 處理錯誤。

練習

至少將電話號碼程式更新,因此如果使用者不在選單輸入任何資料,它不會崩潰。


結語

我現正為本文新增更多部分,現時我建議看 Guido van Rossum 的 The Python Tutorial,您應該能夠明白一部分。

本教學正在改進中,歡迎對其功能提出任何意見。感謝您的電郵,令我完成大量工作,作出改善及更聆聰意見 :)。

祝您編程愉快,希望它可以改變您的生命及世界。

TODO=[ 'errors','how to make modules','more on loops','more on strings', 'file io','how to use online help','try','pickle','anything anyone suggests that I think is a good idea']


FAQ

不能使用程式輸入
如果您使用的是 IDLE,那麼可嘗試使用指令行。這程式似乎已在 IDLE 0.6 或更新的版本解決。如果您使用的是較舊的 IDLE 版本,可嘗試升級至 Python 2.0 或更新的版本。
有可列印版本嗎?
有,可看看下一個問題。
有 PDF 或 zipped 版本嗎?
有,可往 http://www.honors.montana.edu/~jjc/easytut/  找尋幾個不同的版本。
教學文件以甚麼寫成?
LATEX,可看看 easytut.tex 檔案。
我不能在多於一行的程式輸入。
假如您輸入的程式在您輸入不久便執行,您需要修改一個檔案,而不用在互動模式輸入它們。 (提示:互動模式是有 >>> 在首的模式。)
我的問題在這兒找不到答案。
可電郵我詢問,請給我您所有相關的源程式碼 (即使 (或可能特別是) 程式未能運作)。可包括的有用東西是您正在嘗試做的東西,發生甚麼,您預期會發生甚麼,錯誤訊息,Python 版本,操作系統,以及您的貓是否踏了在鍵盤上。 (我家中的貓喜歡空白鍵及 control 鍵。)
我想以不同的語言讀取它。
我知道的有幾種翻譯,一種是韓文,可在以下連結找到: http://home.hanmir.com/~johnsonj/easytut/easytut.html 。另一種是西班牙文,可在這兒找到: http://www.honors.montana.edu/~jjc/easytut/easytut_es/ 。另一種是意大利文,可在這兒找到: http://www.python.it/doc/tut_begin/index.html 。另一種是希獵文,可在這兒找到: http://www.honors.montana.edu/~jjc/easytut/easytut_gr/ 。有幾個人說他們正在做其他語言如法文的翻譯,但我仍未有他們的消息。如果您已完成了翻譯,或知道有任何翻譯,請將翻譯或連結傳送給我。
在 Python 如何製作 GUI?
您可以使用 http://www.python.org/topics/tkinter/ 的 TKinter  或http://www.wxpython.org/WXPython 。
在 Python 如何製作遊戲?
最佳的方法可能是使用 http://pygame.org/ PYgame。
如何由 Python 程式製作可執行程式?
簡短答案:Python 是可解譯的語言,因此這是沒有可能的。詳盡的回答是,可以透過 Python 解譯器及檔案,將它們連結起來,再分發出去,可以製作類似可執行程式的東西。有關該問題的更多資料,可查看: http://www.python.org/cgi-bin/faqw.py?req=all#4.28
在練習上我需要一些協助
提示,密碼程式需要兩個變數,一個會追縱密碼輸入的次數,另一個會追縱上一個輸入的密碼。此外您可以從 http://www.honors.montana.edu/~jjc/easytut/ 下載解決方案。
最後一項要改變的東西是甚麼及在何時?
2000-Dec-16, 新增錯誤處理章節。
2000-Dec-22, 移除舊有的安裝程序。
2001-Jan-16, 解決程式中的錯誤,在 lists 部分新增範例。
2001-Apr-5, 拼字檢查、語法、新增另一個如何破解程式,修好 PDF 版本的 url。
2001-May-13, 新增除錯章節。
2001-Nov-11, 新增練習,修好語法、拼字檢查,及希望改善一些部分的解釋。
2001-Nov-19, 新增密碼練習,修訂參照部分。
2002-Feb-23, 三次移動密碼練習,將 l 改為 list 範例問題的 list 。在決定式章節新增範例,新增兩個新的練習。
2002-Mar-14, 更改 abs to my_abs,因為 python 現在定義一個 abs 函式。
2002-May-15, 新增有關建立可執行程式的 faq,從 list 範例 新增評論。修好 Axel Kleiboemer打錯的字。
2002-Jun-14, 更改程式令它使用 while true 而不是 while 1,令它更加清晰。
2002-Jul-5, 重寫函式章節,修改 fib 程式,希望可以更清晰。
2003-Jan-3, 為決定式章節新增 average 範例。
2003-Jan-19, 新增有關 a_var 值的評論,修好 average2.py 程式中的錯誤。

有關本文件 ...

Python非編程員教學

本文件使用 LaTeX 2HTML translator Version 2K.1beta (1.48) 產生。

Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999, Ross Moore, Mathematics Department, Macquarie University, Sydney.

指令行參數是:
latex2html -split 3 -local_icons -address 'Josh Cogliati jjc@honors.montana.edu ' easytut.tex

翻譯由 Josh Cogliati 在 2003-03-17 開始。


Josh Cogliati jjc@honors.montana.edu