2020年10月3日星期六

010 趣學Python程式設計 第1部分 學習程式設計 第10章 常用的Python模組

 申明本站飛宇網 https://feiyetopro.blogspot.com/自網路收集整理之書籍文章影音僅供預覽交流學習研究,其[書籍、文章、影音]情節內容, 評論屬其個人行為, 與本網站無關。版權歸原作者和出版社所有,請在下載 24 小時內刪除,不得用作商業用途;如果您喜歡其作品,請支持訂閱購買[正版]謝謝!



10章 常用的Python模組

你在第7章中已經學習到,Python的模組就是一些函數、類和變數的組合。Python用模組來把函數和類分組,使它們更方便使用。例如turtle模組,在前面幾章我們用過它,把函數和類分組,用來創建畫布讓海龜在螢幕上作圖。

當你把一個模組引入到程式中,你可以使用它的所有內容。例如,在第4章我們引入了turtle模組,我們就可以訪問Pen類,我們用它來創建一個代表海龜畫布的物件:


Python
有很多模組,能做各種不同的事情。在這一章裡,我們會看看其中最有用的部分,還會嘗試一些其中的函數。

10.1 使用copy模組來複製

copy模組中包含了制做物件的拷貝的函數。通常,在寫程式時,你會創建新物件,但有時你會想要創建一個新物件,它是另一個物件的複製品,尤其是當創建一個物件需要很多步驟的時候。


例如,假設我們有一個
Animal類,它有一個__init__函數,參數為name(名字)、sepcies(物種)、number_of_legs,還有color


我們可以用下面的代碼創建一個
Animal類的新物件。讓我們來創建一隻粉色,有六條腿的鷹馬,我們叫它harry


假如我們要一群粉色有六條腿的鷹馬呢?我們可以一遍遍重複上面的代碼,也可以使用
copy模組中的copy函數:


在這個例子裡,我們創建了一個物件並把它標記為變數
harry,然後我們創建了這個物件的一個拷貝,並把它標記為harriet。儘管它們屬於同一物種,但它們是兩個完全不同的物件。在這裡它的作用只是少寫幾行代碼,但當物件更加複雜時,拷貝就更有用武之地。

我們也可以創建並拷貝Animal物件的清單。


在前面三行,我們創建了三個
Animal物件並把它們放在harrycarrie,還有billy三個變數中。在第四行上,我們把這些物件添加到清單my_animals中。接下來,我們用copy來創建一個新的列表more_animals。最後,我們列印出more_animals清單中的前兩個物件([0][1])的物種,看看是不是和原來的列表中一樣。我們不用重新創建所有的物件就拷貝出了一個清單。


讓我們來看一下,如果我們改變了原始
my_animals清單中Animal物件的某一個物種,將會發生什麼。原來Python也改變了more_animals列表中的物種。


太奇怪了。我們改的不是
my_animals中的物種嗎?為什麼兩個列表中的物種都變了?

物種都變了是因為copy實際上只做了淺拷貝,也就是說它不會拷貝我們要拷貝的物件中的物件。在這裡,它拷貝了主物件list物件,但是並沒有拷貝其中的每個物件。因此我們得到的是一個新清單,但其中的物件並不是新的,清單more_animals中還是那三個同樣的物件。

同樣用這些變數,如果我們給第一個列表(my_animals)添加一個新的Animal的話,它不會出現在拷貝(more_animals)中。要驗證這一點,可以在增加一個Animal後把每個列表的長度列印出來,像這樣:


如你所見,當我們給第一個列表
my_animals增加一個新的Animal時,它不會增加到這個清單的拷貝more_animals中。當我們列印出len的結果時,第一個清單有4個元素,第二個清單有3個元素。

copy模組中的另一個函數deepcopy,則會創建被拷貝物件中的所有物件的拷貝。當我們用deepcopy來複製my_animals時,我們會得到一個新清單,它的內容是所有物件的拷貝。這樣做的結果是,對於原來清單中Animal對象的改動不會影響到新列表。下面是一個例子:



從列印出來的每個清單中的第一個物件的物種中可以看到,當我們改變原來清單中第一個物件的物種時,拷貝的清單沒有發生變化。

10.2 keyword模組記錄了所有的關鍵字

Python自身所用到的那些單詞被稱為關鍵字keyword),比如ifelse還有forkeyword模組中包含了一個叫做iskeyword的函數,還有一個叫kwlist的變數。函數iskeyword返回一個字串是否為Python關鍵字。變數kwlist包含所有Python關鍵字的列表。

請注意在下面的代碼中,對於字串if來講,函數iskeyword返回True,對於字串ozwald,則返回False。列印kwlist變數時你會看到所有關鍵字的列表。新版(或舊版)的Python關鍵字可能會有所不同。


你可以在附錄中找到每個關鍵字的簡介。

10.3 用random模組獲得亂數

random模組中有幾個用來生成亂數的函數,它們的作用有點像讓電腦隨便挑個數位random模組中最有用的幾個函數是randintchoice,還有shuffle

10.3.1 用randint來隨機挑選一個數字

randint函數在一個數位範圍內隨機挑選一個數字,比如在1100之間,1001 000之間,或者10005000之間。下面是一個例子:


你可以用
randint來寫一個簡單(但很無聊)的猜數字遊戲,要用到while迴圈,如下:


首先,我們引入
random模組,然後我們用randint得到一個範圍在1100之間的亂數並將其賦值給變數num。然後我們在行 創建一個永遠執行的while迴圈(除非玩家猜對了數位)。


接下來,我們在行
 列印一條資訊,然後在行 input從使用者那裡得到輸入並放到變數guess中。在行 我們用int把輸入轉換成整數並把它賦值到變數i中。然後在行 我們讓它與那個隨機選擇的數字做比較。如果輸入與隨機生成的數字相等,在行 我們列印你猜對了並跳出迴圈。如果兩個數字不相等,我們會在行 檢查玩家猜的數字是否小了,在行 檢查玩家猜的是否大了,然後列印出相應的提示資訊。

這段代碼有點長,所以你可能會想把它輸入到一個新的命令列視窗中或者創建一個文字檔,保存起來,然後在IDLE中運行它。下面是如何打開和運行保存起來的程式。

1.打開IDLE,選擇文件打開

2.流覽你保存檔的路徑,點擊檔案名來選中它。

3.點擊打開。

4.在新視窗打開後,選擇運行運行模組

10-1是我們運行程式的結果。


10-1 運行結果

10.3.2 用choice從清單中隨機選取一個元素

如果你想從一個清單中隨機選取一個元素,而不是從一個給定的範圍裡,那麼你可以使用choice。例如,如果你想讓Python幫你選個甜品的話:



看來你要吃核仁巧克力餅了,明智的選擇。

10.3.3 用shuffle來給列表洗牌

shuffle函數用來給清單洗牌,把元素打亂。如果你已經在IDLE中引入了random,並且創建了前面例子中的甜品列表,那麼在下面的代碼中你可以對它使用random.shuffle命令:


把列表列印出來你就可以看到洗牌的結果,它的順序完全不同了。如果你寫的是一個牌類遊戲,可以用這個功能來對一個代表一副牌的列表洗牌。

10.4 用sys模組來控制Shell程式

sys模組中有一些系統函數,用來控制Python Shell程式自身。讓我們來看看如何使用exit函數、stdinstdout物件,還有version變數。

10.4.1 用exit函數來退出Shell程式

可以用exit函數來停止Python Shell程式或者控制台。輸入下面的代碼,你會看到提示對話方塊問你是否要退出。選擇Yes,那麼Shell程式就會關閉。


如果你沒有按照第
1章的說明修改過IDLE的話是不行的,你會看到如下的錯誤資訊:


10.4.2
 從stdin對象讀取

sys模組中的stdin物件(standard input標準輸入的簡寫)會提示使用者輸入資訊,讀取到Shell程式中並在程式中使用。正如你在第7章中見到的,這個物件有一個readline函數,它能讀取從鍵盤輸入的一行文本,直到使用者按了回車鍵。它就像是本章前面我們在猜亂數遊戲中用到的input函數一樣。例如,按下面輸入:


Python
會把字串誰最後笑誰的反應就最慢保存到變數v中。我們把v的內容列印出來驗證一下:


input
readline函數的區別之一是readline可以用一個參數來指定讀取多少個字元。例如:


10.4.3
 用stdout對象來寫入

stdin不同,stdout物件(standard output標準輸出的簡寫)可以用來向Shell程式(或控制台)寫消息,而不是從中讀入。在某些方面,它與print相同,但是stdout是一個檔物件,因此它也具有我們在第9章中用到的那些函數,比如write。下面是一個例子:


注意看,當
write結束時,它返回它所寫入的字元的個數。你可以看到在Shell程式中消息的最後列印出52。我們可以把這個值保存到變數中作為記錄,來看看我們總共在螢幕上列印出多少個字元。



10.4.4
 我用的Python是什麼版本的

變數version表示Python的版本,可以用來確定你的Python是否為最新版本。有些程式師喜歡在程式啟動時列印一些資訊。例如,你可能想把Python的版本資訊放到程式的關於視窗中,如:

10.5 用time模組來得到時間

Pythontime模組中包含了表示時間的函數,不過可能和你期望的不太一樣。試試這個:


time()的調用所返回的數字實際上是自19701100:00:00AM以來的秒數。單獨看起來,這種罕見的表現形式沒法直接使用,但它有它的目的。例如,想要計算你程式的某一部分要運行多久,你可以在開始和結束時記錄時間,然後比較兩個值。讓我們來嘗試算一算列印從0999的所有的數位需要多少時間。

首先,寫一個這樣的函數:



接下來,將
max設置為1 000來調用這個函數:


然後用
time模組修改我們的程式來計算函數運行用了多少時間。


再次調用這個程式,我們得到下面的結果(結果根據系統速度的不同而不同):


它是這樣工作的:在行
 當我們第一次調用time()函數時,我們把返回值賦給了變數t1。然後,從行 開始我們在第三行和第四行迴圈並列印所有的數字。迴圈結束後,在行 我們再次調用time()並把返回值賦給變數t2。因為迴圈要花數秒才結束,t2的值會比t1大,因為它距離197011日更久。在行 t2減掉t1後,我們得到列印所有數字所用的秒數。

10.5.1 用asctime來轉換日期

asctime函數以日期的元組為參數,並把它轉換成更可讀的形式。(還記得嗎?元組就像list一樣,只是它的元素不能改變。)就像你在第7章裡看到的一樣,不用任何參數調用,asctime會以可讀的形式返回當前的日期和時間。


要帶參數調用
asctime,我們首先要創建一個包含日期和時間資料的元組。例如,這裡我們把元組賦值給變數t


這一系列數值分別是年、月、日、時、分、秒、星期幾(
0代表星期一,1代表星期二,以此類推)、一年中的第幾天(這裡用0作為一個預留位置),還有它是否為夏令時時間(0代表不是,1代表是)。用一個類似的元組來調用asctime,得到的結果是:


10.5.2
 用localtime來得到日期和時間

asctime不同,函數localtime把當前的日期和時間作為一個物件返回,其中的值大體與asctime的參數順序一樣。如果你列印這個物件,就能看到類的名字,還有其中的每個值,這些值被標記為tm_year(年)、tm_mon(月)、tm_mday(日)、tm_hour(時)等。


要列印當前的年和月,你可以用它們的索引位置(就像對
asctime所用的元組一樣)。從前面的例子中可以看出來,年在第一個位置(位置0)而月在第二個位置(1)。因此,我們可以指定year = t[0]month = t[1],像這樣:


看到了吧,現在是
20202月。

10.5.3 用sleep來休息一會兒吧

當你想推遲或者讓你的程式慢下來時,可以用sleep函數。例如,我們可以嘗試用下面的迴圈來每隔一秒列印出每一個160的數字:



這段代碼可以快速地把
160所有的數位都列印出來。然而,我們可以在每個print語句間都調用sleep來停上1秒鐘,像這樣:


這樣在顯示每個數位時都有一個延遲。在第
12章中,我們會用sleep函數來讓一個動畫看上去更真實。

10.6 用pickle模組來保存資訊

pickle(原意為"醃菜")模組用來把Python物件轉換成可以方便寫入到檔和從檔讀取的形式。如果你在寫一個遊戲並且想保存玩家的進度資訊的話,可能就會用得上pickle。例如,下面是如何給遊戲增加一個保存功能:



這裡,我們創建了一個
Python字典,包含了在我們想像的遊戲中玩家的當前位置、玩家口袋裡和背包裡物品的列表,還有玩家所帶的金錢數量。我們可以把這個字典保存到檔裡,只要以寫入方式打開檔然後調用pickle裡的dump函數,像這樣:


我們在行
 引入pickle模組,然後在行 建立一個遊戲資料的字典。在行 我們用參數wb打開檔save.dat,也就是告訴Python以二進位模式寫入檔(像在第9章裡一樣,你可能要把它放到如/Users/malcolmozwald/home/susanb,或者C:\User\JimmyIpswich這樣的目錄裡)。在行 ,我們把字典和檔變數作為兩個參數傳給dump。最後,在行 我們關閉檔,因為我們已經使用完畢。


純文字檔中只可以包含人們可讀的字元。圖像、音樂檔、電影,還有序列化(被
packle過)的Python物件中的資訊並不總是對人可讀的,所以它們被稱為二進位檔案。如果你打開save.dat檔,你會看到它看上去不像個文字檔,而是一個亂七八糟的混合體,包含一些普通的文本和特殊的字元。


我們可以用
pickleload函數來把寫入的檔反序列化。當我們反序列化時,就是做與序列化相反的操作:把寫到檔中的資訊還原成我們的程式可以使用的值。這個過程有點類似於使用dump函數。


首先,用
rb作參數打開檔,也就是讀取二進位模式。然後把檔傳給load函數並把返回值賦給變數loaded_game_data。最後,關閉檔。

讓我們來驗證一下保存的檔是否被正確地取回了,所以要列印變數:


10.7
 你學到了什麼

在這一章裡,你學習了Python模組是如何組織函數、類和變數的,還有如何引入模組來使用這些函數。你瞭解到了如何拷貝物件,生成亂數,還有隨機為物件清單洗牌,以及如何在Python中使用時間。最後,你學會了如何用pickle在檔中保存和讀取資訊。

10.8 程式設計小測驗

Python的模組完成以下練習。答案可以在網站http://python-for-kids.com/ 上找到。

#1:複製車

下面的代碼會列印出什麼?


#2
:序列化你的最愛

創建一個你最喜愛的東西的列表,然後用pickle把它們保存到favorites.dat文件中。關閉Python Shell程式,再重新打開,通過讀取檔來顯示你的最愛清單。

 

0 留言:

發佈留言