●大標●
Python 之旅 (二)
文/馬兒 (marr@linux.org.tw)
先聲明一下,看完「Python 之旅」並不會馬上讓每位朋友成為 Python 高手,這應該不是本專欄的用意,不過,引發讀者對 Python 的興趣,讓大家一窺 Python 的應用實況,卻是這一系列內容的企圖。「Python 之旅」主要定位為導讀的角色,希望在本專欄告一段落之際,讀者已具備應用 Python 的興趣及預備進階的實力,屆時配合其他文件或書籍,相信能夠達到快速吸收的效果。
行遠必自邇,接下來的內容,將按部就班地介紹幾種基本的資料型別、流程控制、語法結構、內建函式等,練功紮馬步的工夫是省不了的,僅管可能乏味些,但透過實例操作,並和作業系統環境結合,希望能儘量與日常應用搭配,讓「Python 心法」更容易地融入讀者的腦筋迴路。
文中的範例,原則上都在 Mandrake Linux 7.2 環境裡執行與測試,適用於其他版本的 GNU/Linux 應該並無問題,我將預設讀者對於 Linux 已經具備基本之認識,特別是 shell 環境的操作,以及檔案系統結構的認識,另外,C 語言的基本觀念與技巧,也會有助於 Python 的學習,比如說,事先看過 A Book on C (作者是 Al Kelley 與 Ira Pohl) 的內容。這些簡單的先備知識,可以成為多種程式語言學習背景支撐,建議讀者不妨抽空予以納入。
●中標●
從內建資料型別 numbers 談起
Python 的數值資料型別基本分為四類:
數值資料型別 |
範例 |
1. 整數 (Plain Integers) |
7, -7, 256 |
2. 長整數 (Long Integers) |
7L, 10L, -777777777777L |
3. 浮點數 (Floating Point Numbers) |
7.0, 2e8, -7e10 |
4. 複數 (Complex Numbers) |
3+2j, -4-2j, 4.2+6.3j |
Python 裡的整數型別,是以 C 語言的 long 型別來實作,也就是 32 bits 的精準度。直接依序看些操作範例:
example$ python
Python 1.5.2 (#1, Sep 30 2000, 18:08:36) [GCC 2.95.3 19991030 (prerelease)] on linux-i386
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> x = 5 + 14 / 7 - 3 * 2
>>> x
1
>>> 5 / 2
2
>>> 5.0 / 2
2.5
>>> 2 ** 8
256
可愛的四則運算。
別驚慌,5 / 2 答案是 2,這是正常的,如果你想得到 2.5 這樣的答案,應用浮點數型別即可,只要搞清楚其運算的特性,Python 能夠跑出相當令人滿意的答案。
** 代表「指數運算」,所以此處指的就是 28。
關於長整數所使用的 L 符號,事實上也可以用小寫的 l 符號,不過還是建議使用大寫的 L 符號,因為 1l 看起來實在太像 11 了。
>>> 10 ** 9
1000000000
>>> 10 ** 10
Traceback (innermost last):
File "<stdin>", line 1, in ?
OverflowError: integer pow()
>>> 10L ** 10
10000000000L
>>> x = 2147483647
>>> x
2147483647
>>> x + 1
Traceback (innermost last):
File "<stdin>", line 1, in ?
OverflowError: integer addition
OverflowError 就是指該型別「數值滿溢」的錯誤,1010 對整數型別而言已吃不消。
使用長整數後,其結果幾乎已經到達「予取予求」的地步,其有效範圍只跟記憶體容量有關。
x86 PC 上,一般整數型別的最大極限為 231 - 1,即 214783647。
一旦超過 214783647 後,即顯示整數型別的滿溢錯誤。
例如 10L ** 100000 可就讓我的 PIII CPU 忙上好一陣子了 (大約一分鐘餘)。有興趣的朋友,可以試著以 time 來計時玩玩看。
example$ cat power_test1.py
print 10L ** 10000
example$ cat power_test2.py
print 10L ** 100000
example$ time --output=pt1 python power_test1.py
example$ time --output=pt2 python power_test2.py
Python 裡的浮點數型別,是以 C 語言的 double 型別為基礎來實作,我們可以透過 Python 的長整數來模擬許多浮點數計算的技巧,這在要求位數精準的場合上很實用,不過原則上,直接應用浮點數是來得更具效率。
>>> 7.3 ** 2.4
118.025232408
>>> 3.5e8 * 2.0e7
7e+15
>>> x = 1.00000000001
>>> x
1.00000000001
>>> x = 1.000000000001
>>> x
1.0
科學記號的運算。
超過精準位數的話,就會被截掉,使用時要小心。
下列是複數的運算,天啊,喚起我國中時代的回憶。
>>> x = (3 + 2j) * (4 + 9j)
>>> x
(-6+35j)
>>> x.real
-6.0
>>> x.imag
35.0
複數的指定方式,只需要在某個整數或浮點數之後,接個 j 或 J 符號即完成。
分別呼叫 x 的「實部」與「虛部」數值,這是應用了「物件 x」的屬性 (attribute) 功能。
拿 Python 的直譯器當作計算機來用,也是非常方便。
>>> tax = 6.5 / 100
>>> price = 250
>>> price * tax
16.25
>>> price + _
266.25
特別注意到上述的 _ (底線) 符號,它代表的是前一個計算值的結果。
還可以呼叫一些內建函式或載入函式模組。
>>> round(3.14159, 4)
3.1416
>>> abs(-3.000000001)
3.000000001
>>> import math
>>> math.sqrt(2)
1.41421356237
round() 是內建函式,可傳回你想要的四捨五入精準位數值。
abs() 也是內建函式,可傳回絕對值。
import math 就是載入 math 函式模組,隨後便可呼叫其 sqrt() 開平方根功能。
以下的例子是載入 cmath 函式模組,以取得更多數值應用 (大抵用於處理 complex numbers) 的功能協助,其傳回值屬於複數型別。隨 Python 程式所安裝的系統檔案裡,就應該找得到一份 test_cmath.py 的測試範例。
example$ /usr/lib/python1.5/test/test_cmath.py
Calling sin(1.000000) = 0.841471
Calling log10(1.000000) = 0.000000
Calling acos(1.000000) = 0.000000
Calling asinh(1.000000) = 0.881374
Calling acosh(1.000000) = 0.000000
Calling exp(1.000000) = 2.718282
Calling tan(1.000000) = 1.557408
Calling cosh(1.000000) = 1.543081
Calling sqrt(1.000000) = 1.000000
Calling atanh(0.200000) = 0.202733
Calling sinh(1.000000) = 1.175201
Calling tanh(1.000000) = 0.761594
Calling atan(0.200000) = 0.197396
Calling log(1.000000) = 0.000000
Calling cos(1.000000) = 0.540302
Calling asin(1.000000) = 1.570796
PI = 3.14159265359
E = 2.71828182846
●BOX_BEGIN●
●標題●
數值資料型別的進階資訊
有關完整的 number 型別資料,已經被整理於 Python Library Reference [1],有興趣的朋友,歡迎前往挖寶。
另外,為了讓 Python 在幾何學與機械工程運算上能有更佳的表現,歐洲開發人員撰寫了專為科學計算場合應用的 ScientificPython 2.2 模組 [2],其他進階的科學運算技巧,諸如矩陣、行列式、向量運算、多項式運算、線性規劃、3D 繪圖模組等,都可以在此擴充模組中獲得。對於教學人員或是研究人員,應該是相當值得參考的資源。
●BOX_END●
●中標●
流程控制 (Control Flow)
Python 的流程控制,主要由條件式 (conditionals)、迴圈 (loops),以及例外 (exceptions) 所構成,此處的條件式和迴圈,與其他程式語言學習的邏輯觀念並無二致,縱使具有語法技巧上的小差異,其趣味性實在不高,我便不再贅述,讀者手邊若有第 16 期的Linuxer 雜誌,可逕自翻閱參照「Python 簡介」一文的說明。接下來,我將直接以範例程式,帶領讀者認識 Python 流程控制的功能。
下列是一個簡單的複利計算範例程式,程式執行後會輸出計算結果。
example$ cat print_pr.py
principal = 1000
rate = 0.05
num_years = 5
year = 1
while year <= num_years :
principal = principal * (1 + rate)
print year, principal
year = year + 1
值得注意之處,在於 Python 的流程控制語法裡使用了 : (冒號) 符號,以及大量的縮排效果 (indentation and block-structuring),這樣的設計哲學可能跟 C、Perl 等語法相異其趣。
如果有人對於輸出格式不夠滿意的話,可以採用 print "%3d %0.4f" % (year, principal) 敘述式,則可以得到新的輸出結果:
1 1050.0000
2 1102.5000
3 1157.6250
4 1215.5063
5 1276.2816
也就是說,Python 的格式化字串,其處理方式和 C 語言裡的 printf() 函式相仿,
舉例來說,"%3d" 就可以將一個整數欄位,進行寬度為 3 的靠右對齊處理,而 "0.4f" 則可以將一個浮點數設定為四位小數的顯示格式。
配合前述的基礎,我們已經可以撰寫個簡單的 I/O 測試程式囉。
example$ cat high_low.py
number = 78
guess = 0
while guess != number :
guess = input(
“Guess a number: “)if guess > number :
elif guess < number :
example$ python high_low.py
Guess a number: 100
Too high. Try again.
Guess a number: 50
Too low. Try again.
Guess a number: 78
Just right.
下列的範例程式,可以產生每行顯示 16 個字元的 ASCII 表:
example$ cat ascii.py
#!/usr/bin/python
i = 0
while i < 256 :
print chr(i),
if i != 0 and i % 16 == 0 :
i = i + 1
chr() 是 Python 的函式,讀進一個 0 至 256 之間的整數後,會傳回其對應之 ASCII 字元。注意到 chr(i) 後面所接的 , (逗號) 符號,它表示資料以緊接一個空白字元的方式輸出。
i % 16 是為了控制每一行輸出顯示的字元數量。
圖:ascii.py 執行後會顯示 ASCII 表。
●中標●
序數資料 (sequence) 的操作
所謂序數資料型別,就是幾個有序物件的集合,並可以自然數為其索引。Python 的序數型別包含有字串 (string)、串列 (list)、值組 (tuple)。分別介紹如下:
在 Python 當中,只要將幾個文字包含在單引號、雙引號、三引號裡,就可以建立一個字串:
>>> a = 'hello world'
>>> b = "It's nice to learn Python"
>>> c = """
... this is a triple quote demo.
... see? we can go even cross lines :)
... remember to end it with another triple quote.
... """
>>> a[0]
'h'
>>> b[5:18]
'nice to learn'
>>> c[-22:]
'another triple quote.\012'
分別示範的是單引號、雙引號、三引號之字串建立方式。
字串的索引運算可以取得當中的元素 (element),字串 a 裡的元素,是由 0 開始標序,所以 a[0] 是 h,而 a[1] 是 e。
字串的分割運算可以取得元素組。
注意到最後面的 \012,指的是換行符號。
字串某種角度來看,像是「以字元為元素的串列」,因此,有關索引運算,以及分割運算,我會在即將介紹的串列部份中,更加詳細地說明。
●BOX_BEGIN●
●標題●
原始字串 (raw string)
在某一個字串前面加上 r 或 R 字元,可以建立一個原始字串,例如 r
”hello world” 或 R”\the Python user” 等,原始字串經常被使用於 Python 的正規表示式 (regular expression) 場合上,尤其在處理脫逸字元時,是一項實用的特殊用法。●BOX_END●
串列 (list) 是以中括符號為設定格式,先讓我們仔細觀察其操作特性:
>>> x = [1, 2.0, 7, "eleven"]
>>> x[1]
2.0
>>> x[-2]
7
串列裡可以包含多種資料型別,例如數值、字串等,甚至也可以再包含另一個串列在裡頭。例子中的 x 就是一個包含四個元素 (element) 的串列。
串列 x 裡的元素,同樣是由 0 開始標序。
以 -2 來表示從串列的後頭往回標序,所以 x[-2] 是倒數第二個元素資料值。
我們可以使用分割運算 (slice),來截取串列項目裡的某段子集,由於這項操作技巧太實用了,建議讀者不但要搞懂,最好還能熟練。
>>> y = ["first", "second", "third", "fourth"]
>>> y[1:-1]
['second', 'third']
>>> y[:3]
['first', 'second', 'third']
>>> y[-2:]
['third', 'fourth']
>>> y[-2:-3]
[]
以串列 y 為例,其完整的索引 (index) 設定狀況分析如下:
y = |
[ |
"first" |
, |
"second" |
, |
"third" |
, |
"fourth" |
] |
||
↑ |
↑ |
↑ |
↑ |
↑ |
|||||||
正向索引 |
0 |
1 |
2 |
3 |
4 |
||||||
負向索引 |
-4 |
-3 |
-2 |
-1 |
原則上,分割運算是採用 [m:n] 格式,m 為起點,n 為終點,不管是利用正向索引或是負向索引皆可。搭配圖示對照後,可以很輕易地看出 y[1:-1] 指的是
“second” 與 “third” 所組成的子串列,也就稱為串列 y 的一個「切片」(slice)。分割運算若省略「指明的」起點,則代表從最前面的元素取起。
分割運算若省略「指明的」終點,則代表取至最後面的元素為止。
當起點落在終點之後時,分割運算的結果會是空串列。
最後,我們介紹的是值組 (tuple) 型別,乍看之下,它與串列的運作方式類似,不同處在於值組是以小括號符號為設定格式,串列是以中括號為設定格式,而且值組是不可變的物件,串列是可變的物件。
>>> t = ("this", "is", "a", 6, "element", "tuple")
>>> len(t)
6
>>> max(t)
'tuple'
>>> min(t)
6
值組建立的方式與串列相似,同樣可以包含多種型別的元素。
使用內建運算元 len() 取得值組 t 的長度大小。
使用內建運算元 max() 與 min() 取得值組 t 的最大值與最小值。
另外,序數型別既然包括字串、串列、值組三種,在操作應用時,三者是具有共通之運算元的,比如之前已介紹過的索引運算、分割運算,以及 len()、min()、max() 等。
●中標●
物件的可變與不可變
什麼是「可變的」物件呢? 允許使用者對物件進行新增、修改、刪除等動作,該物件則稱為「可變的」物件。事實上,每一種儲存在 Python 程式裡的資料,都是以物件的方式存在,而每一個物件的組成,則包括有識別字、資料型別,以及物件的值。當一個物件建立完畢之後,它的識別字和型別都不可以再更改,但它裡面的值卻有可能被修改,而可以被修改者,就是可變物件 (mutable),否則稱為不可變物件 (immutable)。
>>> a = 256
>>> b = 'Python'
>>> print id(a), id(b)
134957540 134969832
>>> a is b
0
>>> print type(a), type(b)
<type 'int'> <type 'string'>
使用內建函式 id() 可以取得物件的識別字資訊,不過,大致只能得到一長串不甚具備意義的數字,藉以了解 a 與 b 「確實」是兩個不同的物件。
使用 is 運算元可以直接比較兩個物件的識別字是否相同,由於我們知道 a 與 b 的識別字確實不同,因此運算結果是 0。
使用內建函式 type() 可以取得物件的型別資訊。
>>> y = [
“first”, “second”, “third”, “fourth”]>>> id(y)
135309760
>>> y[2] = '3rd'
>>> y.append('5th')
>>> y
['first', 'second', '3rd', 'fourth', '5th']
>>> id(y)
135309760
>>> y.sort()
>>> y
['3rd', '5th', 'first', 'fourth', 'second']
>>> id(y)
135309760
以索引運算來指定想要變更的資料值。
以物件方法 append() 來增加 '5th' 字串到串列 y 的最後面。
以物件方法 sort() 來將串列元素排序。
特別注意到,經過上述的操作及修改過程,串列 y 的識別字仍維持相同,表示串列 y 是可變物件。
●中標●
內建資料型別的概況整理
Python 提供將近二十餘種不同的內建型別,我們目前幾乎只見識到其「冰山一角」,由基本的內建型別出發,將有助於認識所有的資料型別,對於尚未介紹到的資料型別,則希望有興趣的讀者能再持續深入研究。Python 是座寶山,最好是有興趣同行,如此才容易逛出心得。
型別大類 |
型別名稱 |
說明 |
None |
NoneType |
空物件 |
Numbers |
IntType LongType FloatType ComplexType |
整數 長整數 浮點數 複數 |
Sequences |
StringType ListType TupleType XRangeType |
字元字串 串列 值組 由 xrange(i,j,k) 函式傳回值 |
Mapping |
DictType |
辭典集 |
Callable |
BuiltinFunctionType BuiltinMethodType ClassType FunctionType InstanceType MethodType UnboundMethodType |
內建函式 內建方法 類別物件 * 使用者定義函式 類別物件之實例變數 * 物件方法 物件方法 |
Modules |
ModuleType |
模組 |
Classes |
ClassType |
類別定義 * |
Class Instance |
InstanceType |
類別實例變數 * |
Files |
FileType |
檔案 |
Internal |
CodeType FrameType TracebackType SliceType EllipsisType |
編譯位元碼 執行框架 例外追蹤堆疊 由延伸分割所產生的型別 由延伸分割所使用的型別 |
表:內建之 Python 資料型別
* 值得注意的是,ClassType 和 InstanceType 同時分屬於兩類中。
善用 Python 內建之資料型別及物件模型,在專案開發上,是一個相當重要的技術議題,Python 長期以來的改版發展,一大課題便在改善各式物件及資料型別的效率。不過,實務上的做法,在要求效率的場合中,會建議直接以 C 或 C++ 來撰寫程式,然後再匯出成為 Python 的延伸模組。
Integer |
12 bytes |
Long Ingeger |
12 bytes + (nbits/16 + 1) * 2 bytes |
Float |
16 bytes |
Complex |
24 bytes |
List |
16 bytes + 4 bytes * #_elements |
Tuple |
16 bytes + 4 bytes * #_elements |
String |
20 bytes + 1 byte * #_characters |
Dictionary |
24 bytes + 12 * 2n bytes, n = log2(nitems) + 1 |
Class Instance |
16 bytes + dictionary objects |
Xrange |
24 bytes |
表:內建資料型別於 32 位元電腦上的記憶體需求狀況
●中標●
坐擁寶山貴在自知
在 Python 的原始程式碼裡,通常就會附隨相當完整的文件,極富參考價值。只看附隨的文件就足以自學成師,具備此番功力者,應該不是尋常人,不過,不假外求,卻是學習歷程中值得努力的一種境界,這往往代表著一個人獨立思考求解的邏輯能力。為了讓用功的讀者早日認識及習慣 Linux 環境下的自學方式,在此簡介 Python 文件的製作及閱讀方式,相信對於其他的自學機會也能派上用場。
example$ cd /usr/share/doc/python-docs-1.5.2/Doc
此目錄裡存放了許多 .tex 檔案,其實也就是 LaTeX 格式的檔案,已經認識 LaTeX 的朋友,至此應該就能會心一笑,自個兒高興地編譯出 postscript 檔案,而初次遇著 LaTeX 的朋友也無須納悶,
由 .tex 檔案製作出 .ps 檔案的步驟,通常並不難。
example$ make
example$ ls *.ps
api.ps ext.ps lib.ps tut.ps
在一陣 TeX 編譯過程之後,一切順利的話,會看到上述四個 .ps 檔案,即 Postscript 格式的檔案,可以用於預視或直接送交雷射印表機處理。如果你遇到困難的話,八成是 LaTeX 相關套件安裝不完備,先擱著也無所謂。
●BOX_BEGIN●
●標題●
入門 Python 工具書提示
1. Python 技術參考辭典
David Beazley、Guido Van Rossum 著
張裕益 譯
書中第四章內容,即整理了各式資料型別的運算元及表示式,能夠給讀者完整的概念及資訊。而整本書也可以視作精簡的自學手冊,提供平常交叉參考之用。書的尺寸刻意濃縮,用意良善,不過,其排版方式不夠明確,不容易讓人快速尋得所需的資訊。
2. Teach Yourself Python in 24 Hours
Ivan Van Laningham 著
淺顯白話的敘述方式,可以當作入門的教科書,裡頭的範例略顯冗長,主要是訴求新手的直覺式學習,整本書啃起來像是軟麵包一般,易於下嚥。書中的第三部份,專注於介紹 Python GUI 的內容,堪稱一大特色,而第一部份則可做為本文的補充教材,適合有興趣的讀者進一步釐清基本概念。
3. The Quick Python Book
Daryl Harms、Kenneth McDonald 著
解說清晰是本書的特色,我非常喜歡書中的排版方式,加上內容廣度相當大,讓人覺得是一本物超所值的好書。透過諸如 JPython 與 Zope 的介紹,讀者可以見識到 Python 學習後的應用實況。
4. Learning Python
Mark Lutz、David Ascher 著
早期 Python 的入門書籍還不若今日眾多,Learning Python 很長一般時間成為 Python 使用者唯一的正式選擇。這本書直接介紹 Python 核心而重要的部份,大抵都是設計概念層面的內容,依我個人的經驗所示,花大約兩個星期內的時間略讀過它,效益上應會最佳。
●BOX_END●
cd 在 X Window 環境下,可以執行 gv (GhostView) 程式,用以預覽 .ps 檔案內容,如果設定好印表機,執行列印動作後,一份美觀大方的文件便輸出完成。
example$ gv tut.ps
如果有人對英文說明文件感到頭痛,那麼我建議仍試著「略讀」,特別是配合本 Python 專欄的系列介紹後,英文 Python 文件理應不再存有過大的鴻溝。
不過,可惜的是,我未能成功將 *.tex 檔案轉換成 html 檔案格式,途中遭遇到一些狀況,似乎是 latex2html 程式的問題。
只好請讀者們自行前往 http://www.python.org/doc/ 網頁,
線上閱讀 HTML 版本的文件內容。值得注意的是,網站上所謂的 Current Documentation 通常指的是 Python 2.1 版文件,閱讀時請配合自己手邊使用之 Python 程式版本。
Tutorial |
深入淺出的教學手冊。 |
Library Reference |
詳細的函式解說。 |
Language Reference |
Python 語法解說。 |
Extending and Embedding |
說明如何將 Python 程式與其他程式語言進行擴充與結合。 |
Python/C API |
Python 的 C 程式底層介面說明。 |
Macintosh Reference |
專供麥金塔使用者的參考手冊。 |
如果你懶得製作上述的文件,那麼上網同樣可以下載所有的檔案,你可以在 http://www.python.org/doc/current/download.html 網頁裡,下載自己需要的部份:
HTML |
html-2.1.zip (2008 Kb) |
PDF (A4) |
pdf-a4-2.1.zip (3621 Kb) |
PostScript (A4) |
postscript-a4-2.1.zip (1958 Kb) |
LaTeX |
latex-2.1.zip (1000 Kb) |
值得一提的是,Python Tutorial 已有同好譯成中文 [4],翻譯品質極高,歡迎大家多多捧場,並給予譯者一些鼓勵。
●BOX_BEGIN●
●標題●
Python 2.1 問世
截稿之際,適逢 Python 2.1 正式版在網路上誕生,順道在此公告週知。有興趣的朋友可以由 http://www.python.org/ftp/python/2.1/ 下載,Linux 版本原始碼壓縮檔約 4.1 MB,而 Windows 版本安裝檔案約 6.0 MB,完整安裝約需 20 MB 硬碟空間。
從今年初開始進入 alpha 測試階段的 Python 2.1,終於如期在四月間發表正式版,象徵 Python Software Foundation 已成功輔助 Python 的發展。程式語言本身並沒有重大的差異,但在安裝親和度與伴隨之文件更新方面,已更上一層樓。Windows 環境下的使用者,下載新版程式後,可以嘗試直接瀏覽新版的線上文件。
●BOX_END●
●中標●
Python 網路資源
[1] 最新版 Python Library Reference 線上文件
http://www.python.org/doc/current/lib/lib.html
[2] ScientificPython 網頁
http://starship.python.net/crew/hinsen/scientific.html
[3] Python, Random Numbers, and Monte Carlo Simulation
http://www.linuxdev.net/features/articles/ldpymc_1.shtml
[4] 中文 Python 教學文件,譯者署名為 周譯樂
http://coder.9ug.com/language/script/python/tut_tw/tut.html
[5] Non-Programmers Tutorial For Python
http://www.honors.montana.edu/~jjc/easytut/easytut/easytut.html
[6] Python HOWTO Documents
http://py-howto.sourceforge.net/