2e69fa0e3a087f4328f694b0cbf57c26.ppt
- Количество слайдов: 48
Python Tutorial 3 邢育肇 Yu-Tsao Hsing Laboratory for Reliable Computing Department of Electrical Engineering National Tsing Hua University Hsinchu, Taiwan
Procedure (cont. ) · 7/28 Python Tutorial (3) PM 1: 00~4: 00 - 6. Modules - 7. Regular Task · 8/4 Python Tutorial (4) PM 1: 00~4: 00 - 8. Exceptions - 9. Classes 2
6. Modules
Why Modules? · 程式碼的再使用 - 對話模式如果結束Python, 程式碼也會不見 - 模組可以讓我們把程式碼儲存在檔案裡 - 還可以reload · 系統空間名稱分割 - 模組是Python裡最高層次的單元 - 萬人之上 - 是組織系統元件的 具 · 實作共享服務或共享資料 - 若有許多函式會使用相同的資料結構, 可以將此資料 結構寫在module裡面, 再由各個函式自行匯入即可 4
基本概念 · 建立模組: - 只要將程式碼寫到檔案裡, 存成. py即可 - 也可以是C延伸檔案 · 使用模組: - Import:得到一整個完整的模組檔案 - From:可以從某個模組檔案裡取出幾個特定的名稱 - Reload:可重載模組的程式碼而毋須跳離解譯程式 - 另外也可以直接於系統下執行 · 模組搜尋路徑: - Python搜尋模組檔案時, 會檢視存於PYTHONPATH 環境參數中的目錄路徑 - 可以藉由改變模組sys裡面的path來更動 5
基本範例 · 模組可以使用任何一種文書編輯軟體來編輯 · 請一定要以. py作為結尾 · 檔案的名稱一樣受到命名規則的規範 - 無法匯入if. py的模組 · Ex. 有一個名為‘larc. py’的模組檔案 - def printer(x): print x · %python #模組屬性 #進入python 6
基本範例 · >>> import larc #得到模組 · >>> larc. printer(‘Hello python!’) #以評定用法取出名稱 - Hello python! · >>> from larc import printer #得到一次釋出 · >>> printer(‘Hello python!’) #不需要評定取出名稱 - Hello python! · >>> from larc import * #得到全部的釋出 · >>> printer(‘Hello python!’) - Hello python! 7
模組檔案==名稱空間 · 模組的敘述在第一次匯入時執行 - python會建立一個空的模組物件 - 從頭到尾執行一遍 · 最高層次的指定運算建立模組屬性 - 由原先模組裡最高層次的=, def來建立 - 由=建立成員變數, def建立成員函式 - 指定的名稱會存在模組的名稱空間裡 · 模組名稱空間:__dict__ - 模組匯入時建立的名稱空間是辭典 · 模組是獨立的範圍 - 使用必需使用評定方式 - 載入之後一直可以使用 - 與函式只有在執行時存在名稱空間不一樣 8
基本範例二 · Ex. 有一個名為‘larc. py’的模組檔案 - import sys - name = 42 - def func(): pass - print ‘done loading. ’ · >>> import larc. py - done loading. · >>> larc. sys - <module ‘sys’> · >>> larc. name - 42 · >>> larc. func - <function func at 765 f 20> · >>> larc. __dict__. keys() - [‘__file__’, ‘name’, ‘__name__’, #__file__: 模組的檔案名稱 - ‘sys’, ‘__doc__’, ‘__builtins__’, ‘func’] #__name__: 模組名稱 9
名稱評定用法 · 簡單變數 - “X”意指在當前的範圍裡搜尋名稱X(LGB法則) · 評定用法 - “X. Y”意指在X物件中搜尋屬性Y(not範圍) · 評定用法路徑 - “X. Y. Z”意指在X物件中搜尋Y, 然後在物件X. Y中搜尋Z · 跟之前的範圍法則毫無關係 · LGB法則只對無評定用法的名稱生效而已 · 可以將它想像成一個連結到另一個名稱空間的指標 · 評定用法適用於所有有屬性的物件 - 模組, 類別皆適用 - 也算是類別裡繼承(inheritance)的實作 10
匯入模式 · 匯入只發生一次 - 模組在第一次使用import或from時會載入 - 執行模組的程式碼, 會使模組建立其名稱空間 - 之後任何的import和from只會從已載入的模組存取東西 · % cat simple. py · spam = 1 · %python · >>> import simple · >>> simple. spam - 1 · >>> simple. spam = 2 · >>> import simple · >>> simple. spam - 2 11
import和from · 和def一樣, import和from都是可執行敘述, 所以都可以寫在if 敘述內, or 函式內部 · import和from也都是隱性的指定運算 - import會把整個模組指定給一個名稱 - from會把名稱指定給另一個模組中同樣名稱的物件 · from module import *等同於下列程式 · >>> Import module · >>> name 1 = module. name 1 · >>> name 2 = module. name 2 · >>> … · >>> del module 12
指定會碰到的問題 · % cat small. py · x=1 · y = [1, 2] · %python · >>> from small import x, y #複製兩個名稱出來 · >>> x = 42 #只改變區域的x · >>> y[0] = 42 #改變共享的可變更物件 · >>> import small #得到模組名稱 · >>> small. x - 1 #small的x不是區域的x · >>> smal. y - [42, 2] #與區域共享一個可變更物件 13
reload()-introduction · import只會在第一次匯入模組時執行模組的程式碼 - 稍後的import只會使用已載入的模組物件 - reload函式會強迫已經載入的模組程式碼重新執行 · reload是函式不是敘述 · 可以容許程式不中斷 - 並變更部分的程式碼 · 書寫格式 - import module -… - reload(module) -… #匯入模組 #在此改變模組的程式碼 #得到更新後的結果 14
reload()-詳細說明 · reload會在模組的名稱空間裡重新執行模組的程式 碼 - 會覆寫模組已存在的名稱空間 - 不是先刪除舊的名稱空間, 再載入一次 · 最高層次的指定運算會替換對映名稱的內容 · 會影響所有以import來取出模組名稱內容的程式 - reload會替代所有之前位於模組名稱空間裡的數值 · reload只會影響重載之後的from敘述 - 若使用from來取出模組的屬性, 則reload並不會影響 原先持有的數值內容 - 但是reload之後還有from敘述發生, 則程式得到的是 新的內容 15
reload()-範例(1/2) · %cat changer. py · 回到Python解譯程式 · message = “ 1 st version” · >>> import changer · def printer(): · >>> changer. printer() - 1 st version #沒有影響 · print message · 先呼叫一次 · %python · 重新載入模組 · >>> import changer · >>> reload(changer) · >>> changer. printer() - 1 st version · <module ‘changer’> · >>> changer. printer() - 2 nd version #新的結果 · 新開一個視窗編輯changer. py · %cat changer. py · message = “ 2 nd version” 16
模組編譯程式 · python系統稱為解譯程式 - 其實較類似java, 介於編譯程式與解譯程式之間 - 擁有中介形式:位元碼(bytecode) - 擁有一個Visual Machine來執行bytecode · bytecode程式儲存為. pyc副檔名 - 在import過後就會產生 · 對一個模組M來說 - 如果M. py在M. pyc儲存之後沒有任何的變更, 則python將改載 入M. pyc而不是M. py - 如果M. py有更動的話, 則會載入M. py並產生新的M. pyc覆蓋之 前的版本 · 也可以將. pyc視為python程式的封裝版本 - 可擁有資料的隱密性 17
__name__和__main__ · 特殊情況: - 名稱開頭有底線字元就不會被匯入 - 減少名稱空間多餘的匯入 · 每一個模組都有一個內建的屬性:__name__ - 如果檔案當作程式來執行, __name__會設定成”__main__”字串 - 如果檔案當作模組來匯入, __name__會設定成模組的名稱 · __main__在自身測試上最常出現 · %cat tester. py · %python · if __name__==‘__main__’: · · print “This is a program” >>> import tester - This is a module · %python test. py · This is a program · · else: print “This is a module” 18
變更模組搜尋路徑 · · 模組搜尋路徑存在PYTHONPATH的目錄裡 使用sys. path來改變搜尋路徑 >>> import string >>> sys. path - [‘. ’, ‘c: \pythonlib’, ‘c: \python\lib\tkinter’] · >>> sys. path = [‘. ’, ‘c: \book\examples’] #改變搜尋路徑 · >>> sys. path - [‘. ’, ‘c: \book\examples’] · >>> import string - Traceback (innermost last): #因為將pythonlib的路徑刪了 - File “<stdin>”, line 1 , in ? - Import. Error: No module named string · 不要亂刪除python原始的目錄路徑 19
模組設計的概念 · 到處都是模組 - 只要有程式碼, 就有模組 - 事實上, 對話模式也是建構在模組上, 檔名為 __main__ · 減少模組之間的對偶關係(coupling) - 如同函式, 模組寫的越獨立, 運作的越好 - 若模組在另一個模組裡, 要做到不受該模組的廣域變 數影響比較好 · 模組應該盡量不要更改別的模組的變數內容 - 也就是少發生goto的情形 20
恐怖的陷阱-from只複製名稱 · %cat module 1. py · X = 99 · def printer(): print X · %python · >>> from module 1 import X, printer · >>> X= 88 · >>> printer() - 99 · 解決方法: · 使用import方法, 不要用from · >>> import module 1 · >>> module 1. X = 88 · >>> module 1. printer() - 88 21
恐怖的陷阱-程式碼的先後次序 · 由於模組第一次匯入時, 就會從頭到尾執行一次, 所以會有幾個問題: - 位於模組最高層次的程式碼(即不在函式or巢狀敘述裡的部份)在匯入 時就會立刻被執行, 因此這些程式碼絕對不能參考到檔案後面才指定 的名稱 - 位於函式主體的程式碼只有當函式被呼叫時才會執行, 所以在呼叫前 其名稱空間並不存在, 通常可以參考檔案裡的任何名稱 · >>> func 1() · >>> def func 1(): · … · >>> func 1() · >>> def func 2(): · … · >>> func 1() · 解決方法: - 請把def敘述放在檔案最前頭, 把最高層次的程式碼放在檔案的尾部 print func 2(): #錯誤: “func 1”尚未指定 #沒問題: “func 2”稍後才會搜尋 #錯誤: “func 2”尚未指定 return “Hello” #沒問題: “func 1”和“func 1”都指定了 22
恐怖的陷阱-from的遞迴匯入 · · · · · 匯入必須從頭到尾執行一次 - 模組之間彼此互相匯入, 會有問題 - 若模組在匯入另一個模組時, 模組還沒有執行完全, 使得有一些名稱 沒有指定到 %cat recur 1. py X=1 #正確: 有執行 import recur 2 #錯誤: recur 2不存在 Y=2 #未執行 %cat recur 2. py from recur 1 import X #正確: “X”已經指定了 from recur 1 import Y #錯誤: “Y”尚未指定 解決方法: - 歹路不可行阿~~~ - 盡量減少模組循環的次數, 降低模組依存的關係 - 如果一定要, 請延緩模組名稱的存取, 或是擺到函式裡執行 23
恐怖的陷阱-reload會敗給from · 萬惡的淵藪:from - 由於from只會將名稱複製過去, 等於此名稱和原來的 模組失去了聯繫 - reload的重載對from完全無影響力 · 算是module狀態的goto - 如果你的module常常變動需要reload, 請不要用from · from使用的時機: - 只使用一個大模組裡的小函式(節省記憶體) - 小module, 且不常變動(方便不需評定) 24
恐怖的陷阱-reload只有一次 · 當reload時候, python只會重載那個指定的模組檔案, 如果 內部還有匯入模組的敘述, python會當作沒看到 · %cat A. py · import B · import C · %python · >>> … · >>> reload A · 只會reload A, B和C不會重載一次 · 解決方法: - ㄟ……最好不要這樣搞… - 目前學的撇步裡面沒這招!!(還是有解的拉) 25
7. Regular Task
Outline · copy的深入探討 - 辭典的複製 - copy模組 · 排序 · 隨機存取 · 檔案 · 呼叫程式 · 資源 27
辭典的複製 · 串列的複製 - newlist = oldlist[ : ] - 整個切下來複製給newlist - tuple也是相同的作法 · 辭典的複製(1) - new. Dic = { } - for key in old. Dic. keys( ): new. Dic[key] = old. Dic[key] · 辭典的複製(2)(after ver 1. 5) - new. Dic = old. Dic. copy( ) 28
辭典的複製-進階(1/3) · 如果有一個辭典Dic, 你想把Dic的某些內容替換成另一個辭 典other. Dic · 假設 - Dic = {‘micheal’: ‘ 555 -1212’, ‘emily’: ’ 556 -0091’} - other. Dic = {‘latoya’: ’ 555 -1255’, ‘emily’: ’ 667 -1234’} · 最簡單的作法:update() - Dic. update(other. Dic) · 也可以自己寫 - for key in other. Dic. keys(): - Dic[key] = other. Dic[key] · >>> Dic - {‘micheal’: ’ 555 -1212’, ‘latoya’: ’ 555 -1255’, ‘emily’: ’ 667 -1234} 29
辭典的複製-進階(2/3) · · · 如果你希望兩者不要有覆蓋的問題 解決方法 1:遇到覆蓋的部份就跳出 >>> def Merge. Without. Overlap(Dic, other. Dic): … new. Dic = Dic. copy( ) … for key in other. Dic. keys( ): … if key in Dic. keys( ): … print “the two dictionaries are sharing keys!” … return 0 … new. Dic[key] = other. Dic[key] … return new. Dic … >>> new. Dic = Merge. Without. Overlap(Dic, other. Dic) - “the two dictionaries are sharing keys!” 30
辭典的複製-進階(3/3) · 解決方法 2:如果有覆蓋, 就存成tuple · >>> def Merge. With. Overlap(Dic, other. Dic): · … new. Dic = Dic. copy( ) · … for key in other. Dic. keys( ): · … · … · … · >>> new. Dic = Merge. With. Overlap(Dic, other. Dic) · >>> new. Dic - {‘emily’: (‘ 556 -0091’, ’ 667 -1234’), ‘micheal’: ’ 555 -1212’, - ‘latoya’: ’ 555 -1255’} if key in Dic. keys( ): new. Dic[key] = Dic[key], other. Dic[key] else new. Dic[key] = other. Dic[key] return new. Dic 31
copy模組 · +0, +‘ ‘, [: ], . copy可以處理數值, 字串, 串列, 辭典複製的問題, 不過 python仍然有通用的函式可以使用 · copy模組: - copy( ):與之前的複製一樣, 只複製最上層 - deepcopy( ):連內部巢狀資料皆複製 · >>> import copy · >>> list 1 = [{‘name’: ’larc’, ‘dept. ’: ’ee’], 1, ‘tw’, 3. 0] · >>> list 2 = copy(list 1) · >>> list 3 = copy. deepcopy(list 1) · >>> list 1. append(‘nthu’) · >>> list 1[0][‘dept. ’] = ‘eecs’ · >>> print list 1; print list 2; print list 3 - [{‘name’: ’larc’, ‘dept. ’: ’eecs’}, 1, ‘tw’, 3. 0, ‘nthu’] - [{‘name’: ’larc’, ‘dept. ’: ’eecs’}, 1, ‘tw’, 3. 0] - [{‘name’: ’larc’, ‘dept. ’: ’ee’}, 1, ‘tw’, 3. 0] 32
排序(1/2) · 只有串列擁有sort的內建函式 - 其他人呢? · tuple的排序:使用list( )轉成串列 - new. List = list(old. Tuple) - new. List. sort( ) · 辭典的排序: - new. List = old. Dic. keys( ) - new. List. sort( ) · sort用的是python內建的比較方法 - 我們可以定義自己的比較函式 - 只要給定兩個物件, 會傳回-1, 0, 1分別代表<, =, >即可 - 將此比較函式設為sort的引數 33
排序(2/2) · · · · · 做一個不管大小寫的排序方式 >>> def Free. Sort(one, two): … from string import lower … one, two = lower(one), lower(two) … return cmp(one, two) … >>> test. List = [‘this’, ‘A’, ‘sorted’, ‘List’] >>> test. List. sort() >>> print test. List - [‘A’, ‘List’, ‘is’, ‘sorted’, ‘this’] · >>> test. List. sort(Free. Sort) · >>> print test. List - [‘A’, ‘is’, ‘List’, ‘sorted’, ‘this’] 34
random模組 · 最常使用的是choice( ) · 給定一個串列, 它就會隨機挑出其中一個物件 · 若不需要挑出重複物件, 請在挑完後移除該物件即可 · 隨機列印出串列裡所有的物件: · >>> from random import choice · >>> while list 1: · … element = choice(list 1) · … list 1. remove(element) · … print element · … 35
檔案-sys(1/3) · 三種資料流 - sys. stdin:標準輸入 - sys. stdout:標準輸出, 也是print的輸出點 - sys. stderr:標準錯誤 · 範例一:count. py · >>> import sys · >>> data = sys. stdin. readlines() · >>> print “There are”, len(data), “lines in this file. ” · % cat count. py | python count. py - There are 3 lines in this file. 36
檔案-sys(2/3) · 範例二:把開頭#字元的每一列找出來 · >>> import sys · >>> for line in sys. stdin. readlines(): · … if line[0] == ‘#’: print line · 範例三:印出前十列, 後十列, 隔列 · >>> import sys, string · >>> lines = sys. stdin. readlines() · >>> sys. stdout. writelines(lines[: 10]) #首十列 · >>> for line. Index in range(0, len(lines), 2): #取出 0, 2, 4. . · … sys. stdout. write(lines[line. Index]) #取出索引列 37
檔案-sys(3/3) · 範例四:轉置矩陣 · >>> import sys, string · >>> lines = sys. stdin. readlines() · >>> wordlists = [ ] · >>> for line in lines: · … words = string. split(line) · … wordlists. append(words) · >>> for row in range(len(wordlists[0])): · … for col in range(len(wordlists)): · … print wordlists[col][row] + ‘t’, · … print 38
檔案-一次讀一點 · · · 一次讀取一字元 >>> While 1: … next = sys. stdin. read(1) #讀出一個字元的字串 … if not next: #遇到EOF就跳出 … break … #處理next 一次讀取一列 >>> while 1: … next = sys. stdin. readline() #讀出一列的字串 … if not next: #遇到EOF就跳出 … break … #處理next 39
呼叫程式 · python可以當成命令稿語言來使用 · os. system(‘命令列字串’) - 直接呼叫外部程式, 也在外部執行 - 輸出使用標準輸出 · >>> for filename in [‘ 001. data’, ‘ 002. data’]: · … os. system(“cp ”+filename+” ~/”) · 輸出 = os. popen(‘命令列字串’) - 輸出傳回類似file的物件 - 一樣可以使用file的內建函式(read, readlines) 40
呼叫程式-尋找tab字元 · · · >>> import string, os >>> cmd = ‘find. –name “*. py” –print’ >>> for file in os. popen(cmd). readlines( ): … num = 1 … name = file[: -1] #去掉‘n’ … for line in open(name). readlines( ): … pos = string. find(line, “t”) … if pos >= 0: … print ‘File’, name, ‘line’, num, ‘in’, pos, ‘: ’ … print ‘…’, line[: -1] … print ‘…’, ‘ ‘*pos + ‘^’, ‘n’ … num = num + 1 41
網上資源 · http: //docs. python. org/lib/genindex. html 42
Windows資源 · 開始>所有程式>Python 2. 3>Python Manuals 43
還有許多好玩的 · 請參照”python入門“第八章 內建 具 - 內建函式庫 - string模組 - regular expression - os模組 - urllib模組 -… 44
Summery · 模組 · 常見的任務 · 資源 · 別走開…還有~~~~~ 45
Home Work · 寫一個猜數字程式 - 當一個數字對且位置也對, 回應1 a - 當一個數字對但位置不對, 回應1 b · 拿來猜的數字不可以重複 - ex. 1123<~~~不行 · 一邊是你, 另一邊是電腦 - 電腦不能亂猜, 要有AI · 必須有防呆功能 - 輸入的是不是數字要能分辨 - 輸入的是重複的數字也要能分辨 · 附加功能(看你的誠意摟) - 進階防呆功能 可以無限玩 猜的數字可以選擇要幾位數 … 46
Home Work……Plus!! · 加入對戰紀錄 - 紀錄須寫入檔案裡, 累計起來 · 誠意部份 - 可以詢問玩家紀錄是否儲存? - 可以秀出目前的紀錄 - 來個遊戲選單吧 - 破關畫面? ! 47
Rules of HW · 一定要充滿著註解, 變數命名要有意義 · 直接email給我即可 - ythsing@larc. ee. nthu. edu. tw · 繳交期限 - 最後一次上課的前一天(8/3) - 會在最後一次上課時跟大家check · 可以不交 - 交的會有成績給教授(提供參考) - 吳老師的學生一定要交 · 嚴禁抄襲 - 否則…嘿嘿~~~ 48
2e69fa0e3a087f4328f694b0cbf57c26.ppt