小段落


3. An Informal Introduction to Python

在底下的例子裡,你可以很容易區別凡是需要輸入的地方都會出現prompts (">>" 或 "... "),凡是輸出的結果則沒有。如果你想要跟著這個教學文件一起做的話,你就得打入所有在prompts之後的指令,凡是沒有prompts出現的行就是直譯器輸出的結果。值得注意的是,secondary promt 之後如果什麼東西都沒有,表示這是一個空行(直接按ENTER的結果),也表示這是一個多行指令的結束。

在本文件中的大部分例子,都有加上注釋,甚至是那些互動模式下的例子。注釋(comment)在Python中是以 " #" 之後的東西都是注釋(譯:跟Perl一樣)。注釋可以自成一行,也可以跟在空白字元或是程式碼的後面。但是,如果 " #" 是在字串常數(string literal)之中的話,就不代表注釋的意義,而只是一個普通字元罷了。

底下是一些例子:

# this is the first comment
SPAM = 1 # and this is the second comment
# ... and now a third!
STRING = "# This is not a comment."


3.1 把Python當作計算機來用

現在我們來試一試一些簡單的Python指令吧。請先啟動Python的直譯器並且等待primary prompt( " >>" )的出現。(應該不會很久的)


3.1.1 數字

直譯器就好像一個計算機一樣:你可以打入一個表示式(expression),然後直譯器會把這個expression的執行結果秀出來。Expression的語法都很簡單直接,一般的運算符號 +, -, * 以及 / 的用法就跟其他的程式語言(像是Pascal或C)一樣。你也可以用括號 "( )" 來表示運算執行的先後次序。例子如下:

>>> 2+2
4
>>> # This is a comment
... 2+2
4
>>> 2+2 # and a comment on the same line as code
4
>>> (50-5*6)/4
5
>>> # Integer division returns the floor:
... 7/3
2
>>> 7/-3
-3

跟C語言一樣,等於符號 ("=") 其實是表示設定某個值給一個變數的意思。雖然設定 ("=") 運算本身是有結果值的,但是直譯器並不會輸出其結果來。

>>> width = 20
>>> height = 5*9
>>> width * height
900

一個值是可以同時設給許多變數的:

>>> x = y = z = 0  # Zero x, y and z
>>> x
0
>>> y
0
>>> z
0

浮點數的運算在Python裡面也是支援的,如果整數與浮點數(帶小數點或e的數)進行運算的話,整數部分會先轉換(convert)成浮點數再進行運算。

>>> 4 * 2.5 / 3.3
3.0303030303
>>> 7.0 / 2
3.5

甚至連複數的運算也支援喔,只需要把虛數部分加上 "j" 或是 " J"在其後就可以了。如果實部不為零的話,複數的寫法就寫成 "(real+ imagj)" 。或者,我們也可以用函數的方式來表示複數為 "complex(real , imag)" 的形式。

>>> 1j * 1J
(-1+0j)
>>> 1j * complex(0,1)
(-1+0j)
>>> 3+1j*3
(3+3j)
>>> (3+1j)*3
(9+3j)
>>> (1+2j)/(1+1j)
(1.5+0.5j)

複數的虛數部分及實數部分的值都是以浮點數(float point numbers)來表示的,如果 z 代表一個複數的話,你可以很輕易的用 z.real 以及 z.imag 得到一個複數的實數部分及虛數部分。

>>> a=1.5+0.5j
>>> a.real
1.5
>>> a.imag
0.5

複數沒有辦法直接用 (float(), int() 或是 long()) 轉換成浮點數或是整數。事實上,複數沒有直接對應的實數,你必須用 abs(z) 來得到 z 的magnitude(以浮點數表示),或是如上所述 用z.real 直接得到其實數部分。

>>> a=1.5+0.5j
>>> float(a)
Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: can't convert complex to float; use e.g. abs(z)
>>> a.real
1.5
>>> abs(a)
1.58113883008

在互動模式之下,最後一個印出來的expression的值會儲存在一個特殊變數 "_ " 之中。這表示,當你用Python的直譯器來當作計算機用的時候,想要連續做運算其實是方便許多的。如下例:

>>> tax = 17.5 / 100
>>> price = 3.50
>>> price * tax
0.61249999999999993
>>> price + _
4.1124999999999998
>>> round(_, 2)
4.1100000000000003

對於使用者來說, "_" 這個變數是一個唯讀的變數。你沒有辦法設定一個值給它,當你這樣做的時候,事實上你是重新創造一個同名的變數,但是跟之前系統內建的 "_" 這個變數是一點關係也沒有的了。


3.1.2 字串

除了數字之外, Python也有能力處理字串(string)。字串在Python中有很多種表達方式,它可以放在雙括號””之中,也可以放在單括號’’裡面:

>>> 'spam eggs'
'spam eggs'
>>> 'doesn\'t'
"doesn't"
>>> "doesn't"
"doesn't"
>>> '"Yes," he said.'
'"Yes," he said.'
>>> "\"Yes,\" he said."
'"Yes," he said.'
>>> '"Isn\'t," she said.'
'"Isn\'t," she said.'

字串常數(string literals)是可以跨越多行的,其表示方法有很多。如果要換行的話可以用”\”符號來表示之。如下例:

hello = "This is a rather long string containing\n\
several lines of text just as you would do in C.\n\
Note that whitespace at the beginning of the line is\
significant.\n"
print hello

這個例子會印出以下的結果:

This is a rather long string containing
several lines of text just as you would do in C.
Note that whitespace at the beginning of the line is significant.

你也可以用成對的三個單引號( """ ) 或雙引號 ( ''' ) 來表示字串。在此情況下你所打入的ENTER就會直接被解讀為換行符號而不需要再用\n了。

print """
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
"""

這個例子會印出以下的結果:

Usage: thingy [OPTIONS] 
-h Display this usage message
-H hostname Hostname to connect to

如果你打入的expression是字串的運算,運算的結果的同樣的會由直譯器顯示出來,而且顯示的方式跟你直接打入字串常數(string literals)是一樣的:會在引號之中,所有有escape character “\”表示的字元都會依樣的顯示出來。如果字串本身包含有單引號,整個字串就會用雙引號括起來,要不然就會只用單引號來把整個字串括起來。(如果你使用 print 這個敘述(statement)來印出字串的話,螢幕的輸出就不會有引號出現,而且字串中的escape character (\”表示的特殊字元) 都會顯示出其所代表的意義來。)

字串可以用 + 這個運算元來相加 (連接起來),或是用 * 這個運算元來重複之。請看例子:

>>> word = 'Help' + 'A'
>>> word
'HelpA'
>>> '<' + word*5 + '>'
'<HelpAHelpAHelpAHelpAHelpA>'

如果你把兩個字串常數放在一起,它們自動就會相加起來。所以,上面的例子的第一行也可以寫作 "word = 'Help' 'A'" 。不過這個方法只適用於兩個字串常數的相加,其他情況就不適合了。請看例子:

>>> import string
>>> 'str' 'ing' # <- This is ok
'string'
>>> string.strip('str') + 'ing' # <- This is ok
'string'
>>> string.strip('str') 'ing' # <- This is invalid
File "<stdin>", line 1
string.strip('str') 'ing'
^
SyntaxError: invalid syntax

如同在C語言一樣,字串是有標記(subscript(index))的,第一個字元的標記(subscript(index))就是0。在Python中沒有另外一個字元character資料型態,一個字元就是一個長度為 1的字串。就像是在Icon語言一樣,字串是可以用其subscript(index)來切出( slice notation )其中的一部份的,其語法為 ""。

>>> word[4]
'A'
>>> word[0:2]
'He'
>>> word[2:4]
'lp'

與C不同的是,Python的字串是不可改變的(immutable),如果你想要改變其中的一個字元或是一個部份(slice),你會得到一個錯誤的信息:

>>> word[0] = 'x'
Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: object doesn't support item assignment
>>> word[:-1] = 'Splat'
Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: object doesn't support slice assignment

但是你可以任意使用一個字串的一個字元或是一個部份(slice)來創造出另一個字串,這是完全可行的:

>>> 'x' + word[1:]
'xelpA'
>>> 'Splat' + word[-1:]
'SplatA'

當你用字串切片(string slice)的語法時,可以使用其預定(default)的subscript(index)值,這是很方便的。第一個subscript(index)的預設值是0,第二個subscript(index)的預設值則是這個字串的整體長度。

>>> word[:2]    # The first two characters
'He'
>>> word[2:] # All but the first two characters
'lpA'

所以, s[:i] + s[i:] 會恰好等於 s 。你可以想一想為什麼:

>>> word[:2] + word[2:]
'HelpA'
>>> word[:3] + word[3:]
'HelpA'

如果你用一些奇怪的index來切割字串,Python直譯器也都處理的很好:如果第二個index太大的話就自動代換為字串的長度,如果第二個index比第一個index還要小的話就自動傳回 一個空字串。

>>> word[1:100]
'elpA'
>>> word[10:]
''
>>> word[2:1]
''

字串的index甚至可以是負數,若是負數的話,就必須從字串的尾巴開始算起。如下例:

>>> word[-1]     # The last character
'A'
>>> word[-2] # The last-but-one character
'p'
>>> word[-2:] # The last two characters
'pA'
>>> word[:-2] # All but the last two characters
'Hel'

但是 -0 事實上是等於 0 ,所以不會從尾巴開始算起。

>>> word[-0]     # (since -0 equals 0)
'H'

如果負數index超過字串的範圍的話,就自動只會到最大可能的範圍,但是如果不是切割一部份的話就會造成錯誤的情形:

>>> word[-100:]
'HelpA'
>>> word[-10] # error
Traceback (innermost last):
File "<stdin>", line 1
IndexError: string index out of range

最好避免錯誤的方法是把index看成是指向字元及字元間位置的指標,字串的最開頭是0,字串的結尾處就是字串的長度。如下圖所示:

 +---+---+---+---+---+ 
| H | e | l | p | A |
+---+---+---+---+---+
0 1 2 3 4 5
-5 -4 -3 -2 -1

上圖的數字部分第一行代表的是正數的index,由0到字串的長度,第二行代表的是負數的index。字串的切片(slice)很容易就可以看出來,就是兩個index之間的所有字元組合成的字串囉。

對於正數的index來說,如果兩個index都在範圍之內,字串的切片(slice)的長度就正好是其兩個index相減的結果。舉例來說 word[1:3] 的長度就正好是 2。

Python內建的 len() 函式可以幫助我們得到字串的長度值。

>>> s = 'supercalifragilisticexpialidocious'
>>> len(s)
34


3.1.3 Unicode 字串

從Python 2.0 開始Python支援一種新的儲存文字資料的資料型態:Unicode物件(object)。使用這個物件你可以儲存並控制Unicode的資料(詳見 http://www.unicode.org [off-site link] ) ,並且這個物件跟已經存在的字串(string)物件是完全可以互相整合,並且在需要時可以互相轉換的。

使用Unicode的好處是可以處理各種不同國家語言的字元。在Unicode之前,在一個code page裡只有256個字元可以使用在script中。這個限制的結果常常造成軟體國際化(internationalizetion,通常寫作 "i18n" -- "i" + 18個字元 + "n")時候的困擾。Unicode的出現定義一個所有script都可以用的code page,如此就解決了這個問題。

在Python中要創造一個Unicode字串就跟創造一個普通字串一樣容易:

>>> u'Hello World !'
u'Hello World !'

在引號之前小寫的 "u" 代表這個字串是一個Unicode字串。如果你要用到特殊字元,你可能要使用Python的Unicode特殊字元編碼( Unicode-Escape encoding)。底下的範例示範如何使用之:

>>> u'Hello\\u0020World !'
u'Hello World !'

上面的
u0020
表示在這個位置要插入一個由十六位元0x0020所代表的Unicode字元 (就是空白字元啦)。

其他的字元也是一樣的會被解讀為其對應的Unicode字元。由於Unicode對應中的前256 個Unicode字元正好就是大部分歐美國家使用的Latin-1 編碼字元,所以其轉換是更加的容易。

對於專家們來說,有一個字串的原始模式(raw mode)可以使用。你必須再加上一個小寫 'r' 來使Python 使用這一個原始的Unicode特殊字元編碼( Raw-Unicode-Escape encoding)。只有當
uXXXX
之中的小寫 'r' 有奇數的'\'時才會用到這一個編碼的。

>>> ur'Hello\u0020World !'
u'Hello World !'
>>> ur'Hello\\u0020World !'
u'Hello\\\\u0020World !'

這個原始模式(raw mode)通常用在當你的字串裡面有一大堆的反斜線 '\' 時 ,例如regular expressions(正規表示)時就常用到。

除了這些標準的編碼之外, Python還提供了一整套的方法讓你可以從以知的編碼中創造出Unicode字串來。

Python內建的 unicode() p() 函式可以讓你使用所有的已註冊的Unicode解碼/編碼系統(codecs (COders and DECoders))。 這個 codes 可以與大部分的系統互相轉換,包括 Latin-1, ASCII , UTF-8 以及 UTF-16 等等。上面所提到的最後兩種系統是可變長度的編碼系統,可以來儲存8位元及16位元的Unicode字元。Python預設使用UTF-8為預設編碼系統。當你印出Unicode或是將Unicode寫入檔案時都會使用到。

>>> u"äöü"
u'\344\366\374'
>>> str(u"äöü")
'\303\244\303\266\303\274'

如果你要使用一個特別的編碼系統,但是要印出對應的Unicode碼時,你可以使用 unicode() 函式,加上這個編碼系統的名稱當作第二個參數。

>>> unicode('\303\244\303\266\303\274','UTF-8')
u'\344\366\374'

如果要把Unicode字串轉換為一般的字串編碼時,可以使用Unicode物件的 encode() 方法(method)。

>>> u"äöü".encode('UTF-8')
'\303\244\303\266\303\274'


3.1.4 列(List)

(譯:硬要翻譯list實在太不方便,我直接用原文囉)

Python能夠了解一些較為 複雜 的資料型態,這些資料型態大多是用來處理一群的其他資料值。最方便使用的要算是 list 了,一個list可以寫成一串由逗號分開的值(東西),然後用角括號括起來便成。放在list裡的東西不需要是同一個資料型態

>>> a = ['spam', 'eggs', 100, 1234]
>>> a
['spam', 'eggs', 100, 1234]

跟字串的index用法相同,list的index也由0開始,同樣你可以用index來切割lists、組合兩個list等等:

>>> a[0]
'spam'
>>> a[3]
1234
>>> a[-2]
100
>>> a[1:-1]
['eggs', 100]
>>> a[:2] + ['bacon', 2*2]
['spam', 'eggs', 'bacon', 4]
>>> 3*a[:3] + ['Boe!']
['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boe!']

與字串不相同的是,字串的個別字元是不可變動的( immutable ),但是list的個別成員是可以自由改變的。

>>> a
['spam', 'eggs', 100, 1234]
>>> a[2] = a[2] + 23
>>> a
['spam', 'eggs', 123, 1234]

你也可以設定一個值或是一個list給一個list的切割部分(slice),但是這樣的結果會改變整個list的長度:

>>> # Replace some items:
... a[0:2] = [1, 12]
>>> a
[1, 12, 123, 1234]
>>> # Remove some:
... a[0:2] = []
>>> a
[123, 1234]
>>> # Insert some:
... a[1:1] = ['bletch', 'xyzzy']
>>> a
[123, 'bletch', 'xyzzy', 1234]
>>> a[:0] = a # Insert (a copy of) itself at the beginning
>>> a
[123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234]

內建的 len() 函式仍然可用在list上面:

>>> len(a)
8

一個list也可以是另一個list的成員(這叫作巢狀list, nested list),參考下例:

>>> q = [2, 3]
>>> p = [1, q, 4]
>>> len(p)
3
>>> p[1]
[2, 3]
>>> p[1][0]
2
>>> p[1].append('xtra') # See section 5.1
>>> p
[1, [2, 3, 'xtra'], 4]
>>> q
[2, 3, 'xtra']

注意前一個例子, p[1] 以及 q 事實上指得是同一個物件。我們在之後還會再討論物件的語法( object semantics )。


3.2 邁向程式設計的第一步

當然Python能做比二加二更有用更複雜的事,例如說,我們可以寫一個程式來印出費氏數列( the Fibonacci series )來:

>>> # Fibonacci series:
... # the sum of two elements defines the next
... a, b = 0, 1
>>> while b < 10:
... print b
... a, b = b, a+b
...
1
1
2
3
5
8

這個範例告訴了我們很多新的事情:


請看 關於此文件… 裡面有關如何給我們建議的說明。