Python Tutorial 第一堂(4)Unicode 支援、基本 I/O by caterpillar | CodeData
top

Python Tutorial 第一堂(4)Unicode 支援、基本 I/O

分享:

Python Tutorial 第一堂(3)哈囉!世界! << 前情

此文件已有新版,詳見〈Python 3 Tutorial 第二堂(1)Unicode 支援、基本 I/O〉。

在第一堂下課之前,來談談 練習 2:哈囉!世界! 做了什麼?為了方便,把範例程式碼再貼過來一下:

# coding=UTF-8
filename = raw_input('檔名:')

f = open(filename, 'r')
b_str = f.read()
f.close()

print b_str.decode('utf-8') # 這是什麼?
print b_str.decode('utf-8').encode('utf-8') # 這是什麼?

Python 的 Unicode 支援

第 1 行是 編碼宣告(Encoding declaration),這是個魔法註解(Magic comment),它告訴 Python 直譯器,這個原始碼檔案是以 UTF-8 來編碼,如果不這麼加上這個魔法註解,Python 2.x 會以 ASCII 編碼來解讀原始碼,那麼就會出現以下錯誤:

SyntaxError: Non-ASCII character '\xe6' in file hello.py on line 1, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

魔法註解中設定了 UTF-8,這是因為在 Ubuntu 12.04 LTS 中,預設採用的文字編碼是 UTF-8。有趣的是,有時我上課會問學員一個問題:「你用的原始碼文字編碼是什麼?」很多學員答不出來,很多人不知道自己作業系統中開個純文字檔編碼是什麼,不知道在整合開發環境(Integrated Development Environment, IDE)中開個原始碼編碼是什麼,當然也就不知道為什麼把 A 專案的原始碼放到 B 專案中程式碼會出現亂碼。

如果你連 UTF-8 是什麼都不知道,那建議你看看我寫的 亂碼 1/2 中這幾篇文件:

 在 Python 2.x,程式中所有文字都是 str 的實例,可以視為代表文字資料的位元組序列(Byte sequence)。例如在 Python 中,可以使用 len 函式來取得序列長度,不過以下的程式會顯示 6,即使 '測試' 是兩個字元:

# coding=UTF-8
text = '測試'
print len(text) # 顯示 6

這是因為 '測試' 這兩個字元,使用 UTF-8 編碼的話,會使用六個位元組,len 函式實際上是計算位元組序列的長度,而不是字元長度。

在 Python 2.x 中,如果想要用 Unicode 來代表文字,也就是想要用 unicode 型態來封裝文字,可以使用 Unicode 字面常量(Unicode literal) 來表示,也就是在文字前置一個 u 符號。例如:

# coding=UTF-8
text = u'測試'
print type(text) # 顯示 "<type 'unicode'>"
print len(text) # 顯示 2

直譯器執行程式時,會使用 unicode 實例來代表文字資料,這點可以從 type 函式得知,它用來探知實例的型態,使用 len 取得一個 unicode 實例的長度時,它會告訴你有幾個字元。

除了使用 Unicode 字面常量來建立 unicode 實例外,在 Python 2.x 中,如果有個 str 的實例,可以使用其 decode 方法,指定 str 的實例代表何種編碼的位元組序列,這樣就可以傳回文字的 unicode 實例。相反地,如果使用 unicode 實例的 encode 方法,可指定編碼取得文字實際編碼後的位元組序列。

在 Python 3.x 中,預設原始碼檔案必須是 UTF-8 編碼。如果原始碼檔案想要是 UTF-8 以外的編碼,同樣必須在第 1 行放置編碼宣告。Python 3.x 中,文字是 str 型態的實例,不過 str 代表的是 Unicode(而不是像 Python 2.x 代表的是位元組序列),下面這個程式在 Python 3.x 中執行的話:

text = '測試'
print(type(text)) # 顯示 "<class 'str'>"
print(len(text)) # 顯示 2

len 表示會有兩個字元。如果想取得文字實際編碼後的位元組序列,可以使用 encode 方法指定編碼,這會傳回一個 bytes 實例,如果有個 bytes 實例,可以使用 decode 指定編碼,傳回代表 Unicode 的 str 實例。例如下圖是在 Python 3.x 互動交談環境中的測試實例:

python-tutorial-the-1st-class-4-unicode-support-basic-input-output-1

如果想知道更多 Python 中有關文字編碼的細節,可以再參考  Python 的編碼 這篇文件。

基本 I/O

接下來看看有關基本 I/O 的部份,你可以使用 open 函式來開啟檔案,開啟時指定存取模式,'r' 表示讀取,'w' 表示寫入,open 函式會傳回 file 實例,使用 read 方法可以讀取檔案內容,以 str 型態傳回,如先前談到,傳回的 str 實際上代表著位元組序列。

以下是個實際的讀取程式範例:

import sys
file = open(sys.argv[1], 'r')
content = file.read()
print content
file.close()

程式第一行匯入(import)了 sys 模組,sys.argv 是個 list,其中儲存了執行程式時的命令列引數(Command line arguments),索引 0 固定都是執行時的模組名稱,而後是跟隨著的引數,例如執行 python hello.py one two three 時,sys.argv[0] 就會是 'hello.py',其餘索引則是 'one''two''three'print 在 Python 2.x 中是個陳述句,用來顯示指定的資料,不使用檔案時,記得使用 close 關閉檔案。

類似地,一個寫入檔案的程式範例如下,write 方法會將文字的位元組序列寫入至檔案中:

import sys
file = open(sys.argv[1], 'w')
file.write('test')
file.close()

如果要逐行讀取檔案呢?可以使用 filereadline 方法,例如逐行讀取一個文字檔案的所有內容,可以在 while 迴圈中進行:

import sys
file = open(sys.argv[1], 'r')
while True:
    line = file.readline()
    if not line: break
    print line
file.close()

如果讀不到東西了,那 readline 會傳回 '',在 if 判斷式中,'' 會被視為 False

while 後加上 : 表示區塊開始,Python 中使用縮排來決定區塊範圍。注意!你可以自行決定縮排字元,但是 Python 中縮排要一致,如果縮排想使用 Tab 字元,那所有原始碼就都要使用 Tab 字元縮排,如果要使用四個空白字元,那所有原始碼就得是四個空白字元來縮排,強制統一縮排,是 Python 的特色,也是 Python 的文化

可以使用 filereadlines 方法一次讀取所有檔案內容,這會傳回 list,每個索引處代表一行內容,一個程式範例是這樣的:

import sys
file = open(sys.argv[1], 'r')
for line in file.readlines():
    print line
file.close()

for in 語法可作用在 list 上,逐一取出 list 中的元素並指定給變數,對於 for line in file.readlines() 是這樣閱讀的:對於 file.readlines() 傳回的 list 中每個元素,將之指定給 line

實際上對於 Python 來說,讀取檔案最好的方式,就是不要去 read,這是什麼意思?是這樣的…

import sys
for line in open(sys.argv[1], 'r'):
    print line

這是 Python 的風格,也是 Python 的文化,這樣的寫法好處就是增加了可讀性,你不用自行使用 close 關閉檔案,這個語法會在 for in 結束後自行關閉檔案file 實例被回收後,檔案就會關閉,for line in open(sys.argv[1], 'r') 是這樣閱讀的:對於開啟檔案的每一行。除了可讀性外,這個語法還能讓讀取更有效率,不過現階段你不用管這些事,只要當這語法背後施了些魔法就好。

整合開發工具

真正開發程式時,你也許會想要使用整合開發工具,在 Python 的世界中,我確實花了些時間去瞭解有沒有主流的整合開發工具,不過事後覺得,在 Python 的世界中,除了團隊因素決定之外,更多時候是個人口味問題,基於課程時間,我就不逐一討論我調查過的那些工具特色為何了,以下列出一些課程前調查過的幾個:

實際上似乎是如此,在 Python 社群中也有過這樣的一條討論:

第一堂課的內容就到這邊了,我們認識了 Python 環境的安裝與準備,寫了第一個 Python 程式,瞭解了一些 Unicode 支援,並看了些基本的 I/O,休息一下!後面要來進入第二堂課,瞭解更多 Python 語言的細節。

參考資源

  • 直譯器的選擇與安裝

http://www.python.org/download/releases/3.0/
http://www.python.org/download/releases/2.7.3/
http://docs.python-guide.org/en/latest/starting/which-python/

  • 準備課程環境

http://docs.python-guide.org/en/latest/starting/install/linux/

  • 程式庫在哪呢?

http://docs.python.org/2/using/cmdline.html

  • Distutils、Distribute 與 Pip 間的關係

http://docs.python.org/2/library/distutils.html
http://pypi.python.org/pypi/distribute
http://pypi.python.org/pypi/pip
http://blog.yangyubo.com/2012/07/27/python-packaging/
http://www.openfoundry.org/tw/tech-column/8536-introduction-of-python-extension-management-tools

  • 哈囉!世界!

http://openhome.cc/Gossip/Python/IOABC.html
http://openhome.cc/Gossip/Encoding/
http://openhome.cc/Gossip/Encoding/Python.html

後續 >> Python Tutorial 第二堂(1)數值與字串型態

分享:
按讚!加入 CodeData Facebook 粉絲群

相關文章

留言

留言請先。還沒帳號註冊也可以使用FacebookGoogle+登錄留言

Duncan Chang09/10

「你不用自行使用 close 關閉檔案,這個語法會在 for in 結束後自行關閉檔案」這句話似乎不適當,很容易誤會。
例中檔案會關閉是因為 file object 被回收,而不是 for ... in 語法有什麼特別之處。

Tzu-ping Chung10/15

文末「後續」的連結壞了

熱門論壇文章

熱門技術文章