Python 2 Tutorial 第二堂(1)數值與字串型態




第二堂上課囉!在知道怎麼撰寫、執行第一個 Python 程式之後,接下來就要瞭解一下 Python 這個程式語言,只不過我們只剩五個小時,因而採取的方式是,在這一個小時很快地瀏覽過 Python 語言的重要基本元素,之後四個小時再從更多實際的範例中瞭解 Python 語言。 那麼,哪些東西才是語言中重要而基本的元素呢?Pascal 之父 Niklaus E. Writh 曾說過:

Algorithms + Data Structures = Programs

演算法與資料結構就等於程式,而一門語言提供的資料型態(Data type)、運算子(Operator)、程式碼封裝方式等,會影響演算法與資料結構的實作方式,因此這一堂對於 Python 語言講解的重點將選定在:
  • 內建型態(Built-in type)、變數(Variable)與運算子(Operator)
  • 函式(Function)、類別(Class)、模組(Module)與套件(Package)

內建型態

在 Python 中,萬物皆物件!不過,物件導向並非 Python 的主要典範(Paradigm),Python 之父 Guido van Rossum 曾言,自己並非物件導向之信徒,在《Masterminds of Programming》書中,Guido van Rossum 說到:

Python 支援程序式的(Procedural)程式設計以及(某些程度)物件導向。這兩者沒太大不同,然而 Python 的程序式風格仍強烈受到物件影響(因為基礎的資料型態都是物件)。Python 支援小部份函數式(Functional)程式設計 -- 不過它不像任何真正的函數式語言。

 無論如何,接下來要認識的內建型態都是物件,像是:
  • 數值型態(Numeric type) - int, long, float, bool, complex
  • 字串型態(String type)
  • 容器型態(Container type) - list, set, dict, tuple
這篇文章中,我們要先來認識數值型態與字串型態 …

數值型態

我們直接進入 Python 互動環境來瞭解這些型態吧!可以使用 type 函式來得知值的型態。首先是數值型態:
~$ python
Python 2.7.3 (default, Aug  1 2012, 05:16:07) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> type(1)      # 1 是什麼型態?
<type 'int'>
>>> type(1L)     # 加上 L 呢?
<type 'long'>
>>> type(111111111111111111111111111111111) # 太長的整數會自動使用 long 型態
<type 'long'>
>>> type(3.14)   # 浮點數是 float 型態
<type 'float'>
>>> type(True)   # 布林值是 bool 型態
<type 'bool'>
>>> type(3 + 4j) # 支援複數的 complex 型態
<type 'complex'>
>>> 2 ** 100     # 2 的 100 次方
1267650600228229401496703205376L
>>>

上面的範例中使用了 ** 運算子進行次方運算,Python 中當然有加(+)、減(-)、乘(*)等運算子,至於除法則有 / 除法(division)運算子與 // 浮點除法(floor division)兩個,在 Python 2.7 中,整數與整數進行 /// 運算會產生整數;然而整數與浮點數進行 / 會保留小數部份,若進行 // 則會截去小數部份:
>>> 10 / 3
3
>>> 10 // 3
3
>>> 10 / 3.0
3.3333333333333335
>>> 10 // 3.0
3.0
>>>

然而不同版本的 Python 2.x 與 Python 3.x 對於 / // 的行為不同,例如在 Python 3.3 中,整數與整數進行 / 卻是會產生浮點數,原因可看看 Python Taiwan 社團的討論
>>> 10 / 3
3.3333333333333335
>>> 10 // 3
3
>>> 10 / 3.0
3.3333333333333335
>>> 10 // 3.0
3.0
>>>

在浮點數精確度的表現上,也有必須注意的地方。例如:
>>> 1.0 - 0.8
0.19999999999999996
>>> print (1.0 - 0.8)
0.2
>>>

多數 CPU 與浮點運算器多採用 IEEE754 浮點數運算(IEEE 754 floating-point arithmetic),某些浮點數本身就有誤差,這是每個程式人都應該知道的事。Python 互動環境在顯示值時,採用制式的(Offical)字串表示,而 print 語句則採用了非正式的(Informal)字串表示;技術上來說,Python 互動環境會利用物件的 __repr__ 方法傳回的字串來顯示,print 語句會利用物件的 __str__ 方法傳回的字串來顯示:
>>> repr(1.0 - 0.8)
'0.19999999999999996'
>>> str(1.0 - 0.8)
'0.2'
>>>

雖然你也可以用 (1.0 - 0.8).__repr__()(1.0 - 0.8).__str__() 來取得字串,不過在 Python 中,底線開頭暗示著你不要直接呼叫或使用,因此上面的示範中,使用 reprstr 函式來取得字串。日後你繼續學習 Python 語言的過程中,你會知道,__repr____str__ 是可以自行定義的。

簡單來說,用 __repr__ 來傳回沒有岐義的(Unambiguous)字串表示,用 __str__ 來傳回具可讀性的(Readable)字串表示。
想要精確地表示浮點數,語言都會提供程式庫,Python 中使用 decimal 模組中的 Decimal 類別來進行處理。例如:
>>> import decimal
>>> a = decimal.Decimal('1.0')
>>> b = decimal.Decimal('0.8')
>>> a - b
Decimal('0.2')
>>> print (a - b)
0.2
>>>

字串型態

如果要在 Python 中表示字串,可以使用 ''"" 包括文字,兩者在 Python 中具相同作用,都可產生 str 實例,可視情況互換。例如:
>>> "Just'in"
"Just'in"
>>> 'Just"in'
'Just"in'
>>> 'c:\workspace'
'c:\\workspace'
>>> "c:\workspace"
'c:\\workspace'
>>>

可以看到,在某些情況下,你不用特別略過(Escape) \ 字元,然而在底下這種情況下就需要了:
>>> 'c:\todo'
'c:\todo'
>>> print 'c:\todo'
c:	odo
>>> print 'c:\\todo'
c:\todo
>>>

可以在字串前加上 r,表示接下來後面是原始字串(Raw string)表示
,這樣 Python 就會忠實表示後續的字串,技術上來說,會自動為你處理需要略過的字元。例如:
>>> r'c:\todo'
'c:\\todo'
>>> print r'c:\todo'
c:\todo
>>>

Python 中的字串不可變(Immutable)
,你無法改變已建立的字串內容;想得知字串實際的位元組序列長度(不一定是字元長度),可以使用 len 函式;可以使用 for 來迭代字串;可以使用 in 來測試字串是否包括某子字串;可以使用 + 來串接字串;可以使用 * 來複製字串。例如:
>>> name = 'Justin'
>>> len(name)
6
>>> for ch in name:
...     print ch
... 
J
u
s
t
i
n
>>> 'Just' in name
True
>>> name + name
'JustinJustin'
>>> name * 3
'JustinJustinJustin'
>>>

可以使用 [] 指定索引來取得字串中的某個字元,索引從 0 開始,可以是正數或負數,負數表示從尾端開始計數,例如 -1 就是最後一個字元, -2 就是倒數第二個字元,依此類推。例如:
>>> lang = 'Python'
>>> lang[0]
'P'
>>> lang[-1]
'n'
>>>

[]
也可以用來切割字串,例如:
>>> lang[1:5] # 取得索引 1 至 5(包括 1 但不包括 5)的子字串
'ytho'
>>> lang[0:] # 省略結尾索引,表示取至尾端
'Python'
>>> lang[:6] # 省略起始索引,表示從 0 開始
'Python'
>>>

[]
還可以指定間距(Gap),例如取索引 0 至 6,每 2 個間距的方式取子字串:
>>> lang[0:6:2]
'Pto'
>>>

'Python'
'P''y' 算一個間距,'y''t' 之間也是一個間距,依此類推 'Python'[0:6:2] 取得的就是 'Pto',將以上對 [] 的運算方式組合在一起,可以得到一個有趣的反轉字串方式 [::-1]
>>> lang[::-1]
'nohtyP'
>>>

如果要進行字串格式化,以下是舊式寫法:
>>> '%d %.2f %s' % (1, 99.3, 'Justin')
'1 99.30 Justin'
>>> '%(real)s is %(nick)s' % {'real' : 'Justin', 'nick' : 'caterpillar'}
'Justin is caterpillar'
>>>

技術上來說,字串物件將 % 定義為格式化操作,可以接受 tupledict 型態,不過這種寫法可讀性不好,從 Python 2.6 之後,建議使用字串的 format 方法來取代 % 操作
>>> '{0} is {1}'.format('Justin', 'caterpillar')
'Justin is caterpillar'
>>> '{real} is {nick}'.format(real = 'Justin', nick = 'caterpillar')
'Justin is caterpillar'
>>> '{0} is {nick}'.format('Justin', nick = 'caterpillar')
'Justin is caterpillar'
>>> import sys
>>> 'My platform is {pc.platform}'.format(pc = sys)
'My platform is linux2'
>>>

容器型態及 ifforwhile 等流程語法,會在下篇文章中說明,建議你也趁這個機會,在 Python 互動環境中,進行上面看到的範例練習。