最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

簡明Python教程·數(shù)據(jù)結(jié)構(gòu)&解決問題

2023-02-13 08:00 作者:琉璃汐陽  | 我要投稿

上一篇專欄

數(shù)據(jù)結(jié)構(gòu)

數(shù)據(jù)結(jié)構(gòu)(Data Structures)基本上人如其名——它們只是一種結(jié)構(gòu),能夠?qū)⒁恍?shù)據(jù)聚合 在一起。換句話說,它們是用來存儲一系列相關(guān)數(shù)據(jù)的集合。

Python 中有四種內(nèi)置的數(shù)據(jù)結(jié)構(gòu)——列表(List)、元組(Tuple)、字典(Dictionary)和集合(Set)。我們將了解如何使用它們,并利用它們將我們的編程之路變得更加簡單。


列表

列表 是一種用于保存一系列有序項(xiàng)目的集合,也就是說,你可以利用列表保存一串項(xiàng)目的序 列。想象起來也不難,你可以想象你有一張購物清單,上面列出了需要購買的商品,除開在 購物清單上你可能為每件物品都單獨(dú)列一行,在 Python 中你需要在它們之間多加上一個逗 號。

項(xiàng)目的列表應(yīng)該用方括號括起來,這樣 Python 才能理解到你正在指定一張列表。一旦你創(chuàng)建 了一張列表,你可以添加、移除或搜索列表中的項(xiàng)目。既然我們可以添加或刪除項(xiàng)目,我們 會說列表是一種可變的(Mutable)數(shù)據(jù)類型,意即,這種類型是可以被改變的。?


有關(guān)對象與類的快速介紹?

雖然到目前為止我經(jīng)常推遲有關(guān)對象(Object)與類(Class)的討論,但現(xiàn)在對它們進(jìn)行稍 許解釋能夠有助于你更好地理解列表。我們將在后面的章節(jié)討論有關(guān)它們的更多細(xì)節(jié)。

列表是使用對象與類的實(shí)例。當(dāng)我們啟用一個變量 i 并將整數(shù) 5 賦值給它時,你可以認(rèn)為 這是在創(chuàng)建一個 int 類(即類型)之下的對象(即實(shí)例) i 。實(shí)際上,你可以閱讀 help(int) 來了解更多內(nèi)容。

一個類也可以帶有方法(Method),也就是說對這個類定義僅對于它啟用某個函數(shù)。只有當(dāng) 你擁有一個屬于該類的對象時,你才能使用這些功能。舉個例子,Python 為 list 類提供了 一種 append 方法,能夠允許你向列表末尾添加一個項(xiàng)目。例如 mylist.append('an item') 將會向列表 mylist 添加一串字符串。在這里要注意到我們通過使用點(diǎn)號的方法來訪問對象。

一個類同樣也可以具有字段(Field),它是只為該類定義且只為該類所用的變量。只有當(dāng)你 擁有一個屬于該類的對象時,你才能夠使用這些變量或名稱。字段同樣可以通過點(diǎn)號來訪 問,例如 mylist.field 。

案例(保存為 ds_using_list.py ):?

輸出:

它是如何工作的?

變量 shoplist 是一張為即將前往市場的某人準(zhǔn)備的購物清單。在 shoplist 中,我們只存 儲了一些字符串,它們是我們需要購買的物品的名稱,但是你可以向列表中添加任何類型的 對象,包括數(shù)字,甚至是其它列表。

我們還使用 for...in 循環(huán)來遍歷列表中的每一個項(xiàng)目。學(xué)習(xí)到現(xiàn)在,你必須有一種列表也 是一個序列的意識。有關(guān)序列的特性將會在稍后的章節(jié)予以討論。?

在這里要注意在調(diào)用 print 函數(shù)時我們使用 end 參數(shù),這樣就能通過一個空格來結(jié)束輸出 工作,而不是通常的換行。

接下來,如我們討論過的那般,我們通過列表對象中的 append 方法向列表中添加一個對 象。然后,我們將列表簡單地傳遞給 print 函數(shù),整潔且完整地打印出列表內(nèi)容,以此來檢 查項(xiàng)目是否被切實(shí)地添加進(jìn)列表之中。?

接著,我們列表的 sort 方法對列表進(jìn)行排序。在這里要著重理解到這一方法影響到的是列 表本身,而不會返回一個修改過的列表——這與修改字符串的方式并不相同。同時,這也是 我們所說的,列表是可變的(Mutable)而字符串是不可變的(Immutable)。

隨后,當(dāng)我們當(dāng)我們在市場上買回某件商品時,我們需要從列表中移除它。我們通過使用 del 語句來實(shí)現(xiàn)這一需求。在這里,我們將給出我們希望從列表中移除的商品, del 語句 則會為我們從列表中移除對應(yīng)的項(xiàng)目。我們希望移除列表中的第一個商品,因此我們使用 del shoplise[0] (要記住 Python 0 開始計(jì)數(shù))。

如果你想了解列表對象定義的所有方法,可以通過 help(list) 來了解更多細(xì)節(jié)。?


元組

元組(Tuple)用于將多個對象保存到一起。你可以將它們近似地看作列表,但是元組不能提 供列表類能夠提供給你的廣泛的功能。元組的一大特征類似于字符串,它們是不可變的,也 就是說,你不能編輯或更改元組。

元組是通過特別指定項(xiàng)目來定義的,在指定項(xiàng)目時,你可以給它們加上括號,并在括號內(nèi)部 用逗號進(jìn)行分隔。?

元組通常用于保證某一語句或某一用戶定義的函數(shù)可以安全地采用一組數(shù)值,意即元組內(nèi)的 數(shù)值不會改變。?

案例(保存為 ds_using_tuple.py ):

輸出:?

它是如何工作的?

變量 zoo 指的是一個包含項(xiàng)目的元組。我們能夠看到 len 函數(shù)在此處用來獲取元組的長 度。這也表明元組同時也是一個序列。?

現(xiàn)在,我們將這些動物從即將關(guān)閉的老動物園(Zoo)轉(zhuǎn)移到新的動物園中。因此, new_zoo 這一元組包含了一些本已存在的動物以及從老動物園轉(zhuǎn)移過去的動物。讓我們回到話題中 來,在這里要注意到元組中所包含的元組不會失去其所擁有的身份。?

如同我們在列表里所做的那般,我們可以通過在方括號中指定項(xiàng)目所處的位置來訪問元組中 的各個項(xiàng)目。這種使用方括號的形式被稱作索引(Indexing)運(yùn)算符。我們通過指定 new_zoo[2] 來指定 new_zoo 中的第三個項(xiàng)目,我們也可以通過指定 new_zoo[2][2] 來指定 new_zoo 元組中的第三個項(xiàng)目中的第三個項(xiàng)目 。一旦你習(xí)慣了這種語法你就會覺得這其實(shí)非常簡單。

包含 0 或 1 個項(xiàng)目的元組

一個空的元組由一對圓括號構(gòu)成,就像 myempty = () 這樣。然而,一個只擁有一個項(xiàng) 目的元組并不像這樣簡單。你必須在第一個(也是唯一一個)項(xiàng)目的后面加上一個逗號 來指定它,如此一來 Python 才可以識別出在這個表達(dá)式想表達(dá)的究竟是一個元組還是只 是一個被括號所環(huán)繞的對象,也就是說,如果你想指定一個包含項(xiàng)目 2 的元組,你必 須指定 singleton = (2, ) 。

?針對 Perl 程序員的提示?

列表中的列表不會丟失其標(biāo)識,即列表不會像在 Perl 里那般會被打散(Flattened)。這 同樣也適用于元組中的元組、列表中的元組或元組中的列表等等情況。對于 Python 而 言,它們只是用一個對象來存儲另一個對象,不過僅此而已。?


字典

字典就像一本地址簿,如果你知道了他或她的姓名,你就可以在這里找到其地址或是能夠聯(lián) 系上對方的更多詳細(xì)信息,換言之,我們將鍵值(Keys)(即姓名)與值(Values)(即地 址等詳細(xì)信息)聯(lián)立到一起。在這里要注意到鍵值必須是唯一的,正如在現(xiàn)實(shí)中面對兩個完 全同名的人你沒辦法找出有關(guān)他們的正確信息。

另外要注意的是你只能使用不可變的對象(如字符串)作為字典的鍵值,但是你可以使用可 變或不可變的對象作為字典中的值?;旧线@段話也可以翻譯為你只能使用簡單對象作為鍵 值。

在字典中,你可以通過使用符號構(gòu)成 d = {key : value1 , key2 : value2} 這樣的形式,來成 對地指定鍵值與值。在這里要注意到成對的鍵值與值之間使用冒號分隔,而每一對鍵值與值 則使用逗號進(jìn)行區(qū)分,它們?nèi)加梢粚ɡㄌ柪ㄆ稹?/p>

另外需要記住,字典中的成對的鍵值—值配對不會以任何方式進(jìn)行排序。如果你希望為它們 安排一個特別的次序,只能在使用它們之前自行進(jìn)行排序。?

你將要使用的字典是屬于 dict 類下的實(shí)例或?qū)ο蟆?

案例(保存為 ds_using_dict.py ):

輸出:

它是如何工作的

我們通過已經(jīng)討論過的符號體系來創(chuàng)建字典 ab 。然后我們通過使用索引運(yùn)算符來指定某一 鍵值以訪問相應(yīng)的鍵值—值配對,有關(guān)索引運(yùn)算符的方法我們已經(jīng)在列表與元組部分討論過 了。你可以觀察到這之中的語法非常簡單。?

我們可以通過我們的老朋友—— del 語句——來刪除某一鍵值—值配對。我們只需指定字 典、包含需要刪除的鍵值名稱的索引算符,并將其傳遞給 del 語句。這一操作不需要你知道 與該鍵值相對應(yīng)的值。?

接著,我們通過使用字典的 item 方法來訪問字典中的每一對鍵值值配對信息,這一操作 將返回一份包含元組的列表,每一元組中則包含了每一對相應(yīng)的信息——鍵值以及其相應(yīng)的 值。我們檢索這一配對,并通過 for...in 循環(huán)將每一對配對的信息相應(yīng)地分配給 name address 變量,并將結(jié)果打印在 for 代碼塊中。

如果想增加一堆新的鍵值—值配對,我們可以簡單地通過使用索引運(yùn)算符訪問一個鍵值并為 其分配與之相應(yīng)的值,就像我們在上面的例子中對 Guido 鍵值所做的那樣。

我們可以使用 in 運(yùn)算符來檢查某對鍵值—值配對是否存在。

要想了解有關(guān) dict 類的更多方法,請參閱 help(dict) 。

?關(guān)鍵字參數(shù)與字典?

如果你曾在你的函數(shù)中使用過關(guān)鍵詞參數(shù),那么你就已經(jīng)使用過字典了!你只要這么想 ——你在定義函數(shù)時的參數(shù)列表時,就指定了相關(guān)的鍵值—值配對。當(dāng)你在你的函數(shù)中 訪問某一變量時,它其實(shí)就是在訪問字典中的某個鍵值。(在編譯器設(shè)計(jì)的術(shù)語中,這 叫作符號表(Symbol Table))?


序列

列表、元組和字符串可以看作序列(Sequence)的某種表現(xiàn)形式,可是究竟什么是序列,它 又有什么特別之處?

序列的主要功能是資格測試(Membership Test)(也就是 in not in 表達(dá)式)和索引 操作(Indexing Operations),它們能夠允許我們直接獲取序列中的特定項(xiàng)目。

上面所提到的序列的三種形態(tài)——列表、元組與字符串,同樣擁有一種切片(Slicing)運(yùn)算 符,它能夠允許我們序列中的某段切片——也就是序列之中的一部分。

案例(保存為 ds_seq.py ):

輸出:?

它是如何工作的?

首先,我們已經(jīng)了解了如何通過使用索引來獲取序列中的各個項(xiàng)目。這也被稱作下標(biāo)操作 (Subscription Operation)。如上所示,每當(dāng)你在方括號中為序列指定一個數(shù)字,Python 將 獲取序列中與該位置編號相對應(yīng)的項(xiàng)目。要記得 Python 0 開始計(jì)數(shù)。因此 shoplist[0] 將獲得 shoplist 序列中的第一個項(xiàng)目,而 shoplist[3] 將獲得第四個項(xiàng)目。

索引操作也可以使用負(fù)數(shù),在這種情況下,位置計(jì)數(shù)將從隊(duì)列的末尾開始。因 此, shoplist[-1] 指的是序列的最后一個項(xiàng)目, shoplist[-2] 將獲取序列中倒數(shù)第二個項(xiàng)目。

你需要通過指定序列名稱來進(jìn)行序列操作,在指定時序列名稱后面可以跟一對數(shù)字——這是 可選的操作,這一對數(shù)字使用方括號括起,并使用冒號分隔。在這里需要注意,它與你至今 為止使用的索引操作顯得十分相像。但是你要記住數(shù)字是可選的,冒號卻不是。?

在切片操作中,第一個數(shù)字(冒號前面的那位)指的是切片開始的位置,第二個數(shù)字(冒號 后面的那位)指的是切片結(jié)束的位置。如果第一位數(shù)字沒有指定,Python 將會從序列的起始 處開始操作。如果第二個數(shù)字留空,Python 將會在序列的末尾結(jié)束操作。要注意的是切片操 作會在開始處返回 start,并在 end 前面的位置結(jié)束工作。也就是說,序列切片將包括起始位 置,但不包括結(jié)束位置。

因此, shoplist[1:3] 返回的序列的一組切片將從位置 1 開始,包含位置 2 并在位置 3 時結(jié) 束,因此,這塊切片返回的是兩個項(xiàng)目。類似地, shoplist[:] 返回的是整個序列。

你同樣可以在切片操作中使用負(fù)數(shù)位置。使用負(fù)數(shù)時位置將從序列末端開始計(jì)算。例 如, shoplist[:-1] 強(qiáng)返回一組序列切片,其中不包括序列的最后一項(xiàng)項(xiàng)目,但其它所有項(xiàng) 目都包含其中。

你同樣可以在切片操作中提供第三個參數(shù),這一參數(shù)將被視為切片的步長(Step)(在默認(rèn) 情況下,步長大小為 1):

你會注意到當(dāng)步長為 2 時,我們得到的是第 0、2、4…… 位項(xiàng)目。當(dāng)步長為 3 時,我們得到 的是第 0、3……位項(xiàng)目。

?你可以在 Python 解釋器中交互地嘗試不同的切片方式的組合,這將幫助你立即看到結(jié)果。序 列的一大優(yōu)點(diǎn)在于你可以使用同樣的方式訪問元組、列表與字符串。


?集合

集合(Set)是簡單對象的無序集合(Collection)。當(dāng)集合中的項(xiàng)目存在與否比起次序或其出 現(xiàn)次數(shù)更加重要時,我們就會使用集合。

通過使用集合,你可以測試某些對象的資格或情況,檢查它們是否是其它集合的子集,找到 兩個集合的交集,等等。?

它是如何工作的?

這個案例幾乎不言自明,因?yàn)樗婕暗氖菍W(xué)校所教授的數(shù)學(xué)里的基礎(chǔ)集合知識。?


引用 2?

當(dāng)你創(chuàng)建了一個對象并將其分配給某個變量時,變量只會查閱(Refer)某個對象,并且它也 不會代表對象本身。也就是說,變量名只是指向你計(jì)算機(jī)內(nèi)存中存儲了相應(yīng)對象的那一部 分。這叫作將名稱綁定(Binding)給那一個對象。

一般來說,你不需要去關(guān)心這個,不過由于這一引用操作困難會產(chǎn)生某些微妙的效果,這是 需要你注意的:?

案例(保存為 ds_reference.py ):

輸出:

它是如何工作的?

大部分解釋已經(jīng)在注釋中提供。

你要記住如果你希望創(chuàng)建一份諸如序列等復(fù)雜對象的副本(而非整數(shù)這種簡單的對象 (Object)),你必須使用切片操作來制作副本。如果你僅僅是將一個變量名賦予給另一個名 稱,那么它們都將“查閱”同一個對象,如果你對此不夠小心,那么它將造成麻煩。

針對 Perl 程序員的提示?

要記住列表的賦值語句不會創(chuàng)建一份副本。你必須使用切片操作來生成一份序列的副本。


?有關(guān)字符串的更多內(nèi)容?

在早些時候我們已經(jīng)詳細(xì)討論過了字符串。還有什么可以知道的嗎?還真有,想必你還不知 道字符串同樣也是一種對象,并且它也具有自己的方法,可以做到檢查字符串中的一部分或 是去掉空格等幾乎一切事情!?

你在程序中使用的所有字符串都是 str 類下的對象。下面的案例將演示這種類之下一些有用 的方法。要想獲得這些方法的完成清單,你可以查閱 help(str) 。

案例(保存為 ds_str_methods.py ):

輸出:

它是如何工作的?

在這里,我們會看見一此操作中包含了好多字符串方法。 startwith 方法用于查找字符串是 否以給定的字符串內(nèi)容開頭。 in 運(yùn)算符用以檢查給定的字符串是否是查詢的字符串中的一部分。

? find 方法用于定位字符串中給定的子字符串的位置。如果找不到相應(yīng)的子字符串, find 會返回 -1。 str 類同樣還擁有一個簡潔的方法用以 聯(lián)結(jié)(Join序列中的項(xiàng)目,其中字符串 將會作為每一項(xiàng)目之間的分隔符,并以此生成并返回一串更大的字符串。


?總結(jié)

我們已經(jīng)詳細(xì)探討了 Python 中內(nèi)置的多種不同的數(shù)據(jù)結(jié)構(gòu)。這些數(shù)據(jù)結(jié)構(gòu)對于編寫大小適中 的 Python 程序而言至關(guān)重要。?

現(xiàn)在我們已經(jīng)具備了諸多有關(guān) Python 的基本知識,接下來我們將會了解如何設(shè)計(jì)并編寫一款 真實(shí)的 Python 程序。?

  1. . 第一個“第三個項(xiàng)目”可以是指元組中的元組。 ??

  2. . 原文作“Reference”,沈潔元譯本譯作“參考”。此處譯名尚存疑,如有更好的翻譯建議 還請指出。 ?

解決問題?

我們已經(jīng)探索了 Python 語言中的許多部分,現(xiàn)在我們將通過設(shè)計(jì)并編寫一款程序來了解如何 把這些部分組合到一起。這些程序一定是能做到一些有用的事情。這其中的方法就是去學(xué)習(xí) 如何靠你自己來編寫一份 Python 腳本。


問題

我們希望解決的問題如下:?

我想要一款程序來備份我所有的重要文件。?

雖然這是一個簡單的問題,但是其中并沒有足夠的信息有助于讓我們開始規(guī)劃一份解決方 案。我們需要進(jìn)行一些分析(Analysis)。例如,我們應(yīng)該如何指定哪些文件是我們需要備份 的?它們應(yīng)該如何進(jìn)行備份?儲存到哪里??

在正確地分析了這些問題過后,我們便開始設(shè)計(jì)(Design)我們的程序。我們將列出一份關(guān) 于我們的程序應(yīng)如何運(yùn)轉(zhuǎn)的清單。在這個案例中,我已經(jīng)編寫了如下清單來說明我將如何工 作。如果由你來設(shè)計(jì)程序,你可能不會做出同樣的分析,因?yàn)槊總€人都有其自己的行事方 式,所以出現(xiàn)不同是完全正常、且正確的。

  • 需要備份的文件與目錄應(yīng)在一份列表中予以指定。

  • 備份必須存儲在一個主備份目錄中。?

  • 備份文件將打包壓縮成 zip 文件。?

  • zip 壓縮文件的文件名由當(dāng)前日期與時間構(gòu)成。?

  • 我們使用在任何 GNU/Linux 或 Unix 發(fā)行版中都會默認(rèn)提供的標(biāo)準(zhǔn) zip 命令進(jìn)行打包。 在這里你需要了解到只要有命令行界面,你就可以使用任何需要用到的壓縮或歸檔命令。?

針對 Windows 用戶的提示?

Windows 用戶可以從 GnuWin32 項(xiàng)目頁面 上下載并安裝 zip 命令,并將 C:\Program Files\GnuWin32\bin 添加至你的系統(tǒng)的 PATH 環(huán)境變量中,這一操作過程與我們?yōu)槭瓜到y(tǒng)識別 Python 命令本身所做的事情相同。?


解決方案?

由于我們的程序設(shè)計(jì)方案現(xiàn)在已經(jīng)相當(dāng)穩(wěn)定,我們便可以開始編寫代碼,這個過程我們稱之 為實(shí)現(xiàn)(Implementation)我們的解決方案。?

將下述代碼保存為 backup_ver1.py :?

輸出:

現(xiàn)在,我們正處于測試(Testing)階段,在這一階段我們測試我們的程序是否能正常工作。 如果其行為不符合我們的預(yù)期,那么我們需要對我們的程序進(jìn)行 Debug 工作,也就是說,移 除程序中的 Bug(錯誤)。?

如果上面的程序不能夠正常工作,復(fù)制打印在 Zip command is 后面的命令,將其粘貼至 shell(在 GNU/Linux Mac OS X 環(huán)境中)或 cmd (對于 Windows 環(huán)境),看看存在什么 錯誤并嘗試將其修復(fù)。同時你還需要檢查 zip 命令手冊來看看是不是哪里存在錯誤。如果這條 命令成功運(yùn)行,那么可能是錯誤可能存在在 Python 程序本身之中,因此你需要檢查你的程序 是否如上面所展示那番。

?它是如何工作的?

你會注意到我們是如何一步步將我們的設(shè)計(jì)轉(zhuǎn)化為代碼的。

?我們首先導(dǎo)入 os time 模塊以準(zhǔn)備使用它們。然后,我們在 source 列表中指定我們需 要備份的文件與目錄。我們需要存儲我們所有備份文件的目標(biāo)目錄在 target_dir 變量中予 以指定。我們將要創(chuàng)建的 zip 歸檔文件的名字由當(dāng)前日期與時間構(gòu)成,在這里通過 time.strftime() 函數(shù)來創(chuàng)建。文件名將以 .zip 作為擴(kuò)展名,并存儲在 target_dir 目錄 中。

在這里要注意 os.sep 變量的使用方式——它將根據(jù)你的操作系統(tǒng)給出相應(yīng)的分隔符,在 GNU/LinuxUnix 中它會是 '/' ,在 Windows 中它會是 '\\' ,在 Mac OS 中它會是 ':' 。使用 os.sep 而非直接使用這些字符有助于使我們的程序變得可移植,從而可以在上 述這些系統(tǒng)中都能正常工作。

time.strftime() 函數(shù)會遵循某些格式(Specification),其中一種就如我們在上方程序中所使用的那樣。 %Y 將被替換成帶有具體世紀(jì)的年份。 %m 將會被替換成以 01 12 的十進(jìn) 制數(shù)所表示的月份。有關(guān)這些格式的全部列表可以在 Python 參考手冊中查詢到。

我們使用連接(Concatenates)字符串的加法( + )運(yùn)算符來創(chuàng)建目標(biāo) zip 文件的文件名, 也就是說,它將兩個字符串連接到一起并返回一個新的字符串。然后,我們創(chuàng)建了一串字符 串 zip_command ,其中包括了我們要執(zhí)行的命令。如果這條命令不能正常工作,你可以把它 拷貝到 ShellGNU/Linux 終端或 DOS 提示符)中進(jìn)行檢查。

我們使用的 zip 命令會有一些選項(xiàng)與參數(shù)需要傳遞。 -r 選項(xiàng)用以指定 zip 命令應(yīng)該遞歸地 (Recursively)對目錄進(jìn)行工作,也就是說它應(yīng)該包括所有的子文件夾與其中的文件。這兩 個選項(xiàng)結(jié)合到一起并可以指定一個快捷方式作 -qr 。選項(xiàng)后面跟著的是將要創(chuàng)建的 zip 文件 的名稱,再往后是需要備份的文件與目錄的列表。我們通過使用已經(jīng)討論過并已了解該如何 運(yùn)用的的字符串方法 join 來將列表 source 轉(zhuǎn)換成字符串。?

隨后,我們終于可以運(yùn)行這一使用了 os.system 函數(shù)的命令,這一函數(shù)可以使命令像是從系 統(tǒng)中運(yùn)行的。也就是說,從 shell 中運(yùn)行的——如果運(yùn)行成功,它將返回 0 ,如果運(yùn)行失 敗,將返回一個錯誤代碼。

根據(jù)命令運(yùn)行的結(jié)果是成功還是失敗,我們將打印出與之相應(yīng)的信息來告訴你備份的結(jié)果究 竟如何。

就是這樣,我們便創(chuàng)建了一份用以備份我們的重要文件的腳本!

針對 Windows 用戶的提示?

除了使用雙反斜杠轉(zhuǎn)義序列,你還可以使用原始字符串。例如使用 'C:\\Documents' r'C:\Documents' 。然而,不要使用 'C:\Documents' ,因?yàn)樗鼘⒈蛔R別為你使用了一個 未知的轉(zhuǎn)義序列 \D 來結(jié)束路徑的輸入。

?現(xiàn)在,我們已經(jīng)擁有了一份可以正常工作的備份腳本,我們可以在任何我們需要備份文件的 時候使用它。這被稱作軟件的操作(Operation)或部署(Deployment)階段。?

上面所展示的程序能夠正常工作,但是(通常)第一個程序都不會按照你所期望的進(jìn)行工 作。可能是因?yàn)槟銢]有正確地設(shè)計(jì)程序,或如果你在輸入代碼時出現(xiàn)了錯誤。出現(xiàn)這些情況 時,在恰當(dāng)?shù)臅r候,你需要回到設(shè)計(jì)階段,或者你需要對你的程序進(jìn)行 Debug 工作。


?第二版?

我們的第一版腳本已經(jīng)能夠工作了。然而,我們還可以對它作出一些改進(jìn),從而使它能夠更 好地在每一天都可以正常工作。我們將這一階段稱之為軟件的維護(hù)(Maintenance)階段。

我認(rèn)為有一種頗為有用的改進(jìn)是起用一種更好的文件命名機(jī)制——使用時間作為文件名,存 儲在以當(dāng)前日期為名字的文件夾中,這一文件夾則照常存儲在主備份目錄下。這種機(jī)制的第 一個有點(diǎn)在于你的備份會以分層的形式予以存儲,從而使得它們能更易于管理。第二個優(yōu)點(diǎn) 是文件名能夠更短。第三個優(yōu)點(diǎn)在于由于只有當(dāng)天進(jìn)行了備份才會創(chuàng)建相應(yīng)的目錄,獨(dú)立的 目錄能夠幫助你快速地檢查每天是否都進(jìn)行了備份。?

保存為 backup_ver2.py :?

輸出:

它是如何工作的?

程序的大部分都保持不變。有所改變的部分是我們通過 os.path.exists 函數(shù)來檢查主文件目 錄中是否已經(jīng)存在了以當(dāng)前日期作為名稱的子目錄。如果尚未存在,我們通過 os.mkdir 函 數(shù)來創(chuàng)建一個。?


第三版?

第二版在我要制作多份備份時能夠正常工作,但當(dāng)備份數(shù)量過于龐大時,我便很難找出備份 之間有什么區(qū)別了。例如,我可能對我的程序或者演示文稿做了重大修改,然后我想將這些 修改與 zip 文件的文件名產(chǎn)生關(guān)聯(lián)。這可以通過將用戶提供的注釋內(nèi)容添加到文件名中來實(shí) 現(xiàn)。

預(yù)先提醒:下面給出的程序?qū)⒉粫9ぷ鳎圆槐伢@慌,只需跟著案例去做因?yàn)槟阋?里面學(xué)上一課。?

保存為 backup_ver3.py

輸出:

?它是如何(不)工作的?

這個程序它跑不起來!Python 會說程序之中存在著語法錯誤,這意味著腳本并未擁有 Python 期望看見的結(jié)構(gòu)。當(dāng)我們觀察 Python 給出的錯誤時,會看見它同時也告訴我們它檢測到錯誤 的額地方。所以我們開始從那個地方開始對我們的程序進(jìn)行 Debug 工作。?

仔細(xì)觀察,我們會發(fā)現(xiàn)有一獨(dú)立的邏輯行被分成了兩行物理行,但我們并未指定這兩行物理 行應(yīng)該是一起的?;旧?,Python 已經(jīng)發(fā)現(xiàn)了該邏輯行中的加法運(yùn)算符( + )沒有任何操作 數(shù),因此它不知道接下來應(yīng)當(dāng)如何繼續(xù)。因此,我們在程序中作出修正。當(dāng)我們發(fā)現(xiàn)程序中 的錯誤并對其進(jìn)行修正時,我們稱為“錯誤修復(fù)(Bug Fixing)”。?


第四版?

保存為 backup_ver4.py

輸出:

它是如何工作的?

現(xiàn)在程序可以正常工作了!讓我們來回顧一下我們在第三版中所作出的實(shí)際的增強(qiáng)工作。我 們使用 input 函數(shù)來接受用戶的注釋內(nèi)容,并通過 len 函數(shù)來檢查輸入內(nèi)容的長度,以檢 查用戶是否確實(shí)輸入了什么內(nèi)容。如果用戶未輸入任何內(nèi)容而直接敲下了 enter 鍵(也許這 份備份只是一份例行備份而沒作出什么特殊的修改),那么我們將繼續(xù)我們以前所做的工作。

不過,如果用戶輸入了某些注釋內(nèi)容,那么它將會被附加進(jìn) zip 文件的文件名之中,處在 .zip 擴(kuò)展名之前。在這里需要注意的是我們用下劃線替換注釋中的空格——這是因?yàn)楣芾?沒有空格的文件名總會容易得多。?


繼續(xù)改進(jìn)?

第四版程序已經(jīng)是一份對大多數(shù)用戶來說都能令人滿意地工作運(yùn)行的腳本了,不過總會有改 進(jìn)的余地在。例如,你可以在程序中添加 -v 選項(xiàng)來指定程序的顯示信息的詳盡 程度,從而 使你的程序可以更具說服力,或者是添加 -q 選項(xiàng)使程序能靜默(Quiet)運(yùn)行。

?另一個可以增強(qiáng)的方向是在命令行中允許額外的文件與目錄傳遞到腳本中。我們可以從 sys.argv 列表中獲得這些名稱,然后我們可以通過 list 類提供的 extend 方法把它們添加 到我們的 source 列表中。

?最重要的改進(jìn)方向是不使用 os.system 方法來創(chuàng)建歸檔文件,而是使用 zipfiletarfile 內(nèi)置 的模塊來創(chuàng)建它們的歸檔文件。這些都是標(biāo)準(zhǔn)庫的一部分,隨時供你在你的電腦上沒有 zip 程 序作為沒有外部依賴的情況下使用這些功能。?

不過,在上面的例子中,我一直都在使用 os.system 這種方式作為創(chuàng)建備份的手段,這樣就 能保證案例對于所有人來說都足夠簡單同時也確實(shí)有用。

?你可以試試編寫第五版腳本嗎?在腳本中使用 zipfile 模塊而非 os.system 調(diào)用。


?軟件開發(fā)流程?

我們已經(jīng)經(jīng)歷了開發(fā)一款軟件的流程中的各個 階段(Phases) ?,F(xiàn)在可以將這些階段總結(jié)如 下:

  1. What/做什么(分析)

  2. How/怎么做(設(shè)計(jì))

  3. Do It/開始做(執(zhí)行)

  4. Test/測試(測試與修復(fù)錯誤)

  5. Use/使用(操作或開發(fā))

  6. Maintain/維護(hù)(改進(jìn))?

編寫程序時推薦的一種方式是遵循我們在編寫備份腳本時所經(jīng)歷的步驟:進(jìn)行分析與設(shè)計(jì); 開始實(shí)現(xiàn)一個簡單版本;測試并修復(fù)錯誤;開始使用以確保工作狀況皆如期望那般?,F(xiàn)在, 你可以添加任何你所希望擁有的功能,并繼續(xù)去重復(fù)這一“開始做—測試—使用”循環(huán),需要做 多少次就去做多少次。?

要記?。?/p>

程序是成長起來的,不是搭建出來的。 (Software is grown, not built.) ——Bill de hóra?


總結(jié)

我們已經(jīng)看到了如何創(chuàng)建我們自己的 Python 程序與腳本,也了解了編寫這些程序需要經(jīng)歷的 數(shù)個階段?;蛟S你會發(fā)現(xiàn)我們在本章中學(xué)習(xí)的內(nèi)容對于編寫你自己的程序很有幫助,這樣你 就能慢慢習(xí)慣 Python,同樣包括它解決問題的方式。?

接下來,我們將討論面向?qū)ο缶幊獭?

  1. 原文作 Verbosity,沈潔元譯本譯作“交互”。 ??

下一篇專欄


簡明Python教程·數(shù)據(jù)結(jié)構(gòu)&解決問題的評論 (共 條)

分享到微博請遵守國家法律
南陵县| 安庆市| 民县| 岫岩| 岑巩县| 枣阳市| 易门县| 奉节县| 洪雅县| 崇信县| 石柱| 涞水县| 镇赉县| 西吉县| 玉屏| 南开区| 宕昌县| 大竹县| 呼图壁县| 夏邑县| 定南县| 衡阳市| 莒南县| 古田县| 武安市| 弥勒县| 隆化县| 思茅市| 英超| 枝江市| 洪洞县| 门源| 泌阳县| 临海市| 大姚县| 商都县| 苍溪县| 甘孜县| 台北县| 普兰店市| 常宁市|