Python程序設(shè)計(jì)基礎(chǔ)第九章 模塊與包_第1頁(yè)
Python程序設(shè)計(jì)基礎(chǔ)第九章 模塊與包_第2頁(yè)
Python程序設(shè)計(jì)基礎(chǔ)第九章 模塊與包_第3頁(yè)
Python程序設(shè)計(jì)基礎(chǔ)第九章 模塊與包_第4頁(yè)
Python程序設(shè)計(jì)基礎(chǔ)第九章 模塊與包_第5頁(yè)
已閱讀5頁(yè),還剩55頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

匯報(bào)人:WPS程序設(shè)計(jì)基礎(chǔ)第九章模塊與包目錄01模塊與包的本質(zhì)02庫(kù)的安裝與導(dǎo)入03Python生態(tài)系統(tǒng)之Pygame庫(kù)04小試牛刀05拓展實(shí)踐:使用模塊組織代碼.

理解模塊與包的概念。.深入理解import語(yǔ)句。.能使用模塊與包組織代碼。學(xué)習(xí)目標(biāo)PART19.1模塊與包的本質(zhì)9.1模塊與包的本質(zhì)我們已經(jīng)知道函數(shù)是完成特定功能的一段程序,為代碼的復(fù)用帶來(lái)方便。如果編寫的多個(gè)函數(shù)具有相關(guān)性,組合起來(lái)可以解決更大的問(wèn)題,如文件路徑的處理或時(shí)間的處理。那這些函數(shù)就可以被組織在一個(gè)代碼文件(以“.py”為擴(kuò)展名)中,整個(gè)代碼文件可以被其他的程序復(fù)用,這個(gè)代碼文件就是一個(gè)模塊。因此Python的模塊沒有什么神秘的,其本質(zhì)就是一個(gè)代碼文件。代碼文件中會(huì)有變量、語(yǔ)句、函數(shù)或類等內(nèi)容。而這個(gè)代碼文件或者說(shuō)模塊可以被其他程序?qū)耄貜?fù)使用,因此模塊的價(jià)值在于代碼復(fù)用。沒有復(fù)用價(jià)值的代碼文件雖然理論上也是一個(gè)模塊,但意義不大。9.1模塊與包的本質(zhì)如果函數(shù)或類比較多,組織在一個(gè)代碼文件中會(huì)過(guò)于沉重,則會(huì)被分散到多個(gè)代碼文件。這多個(gè)代碼文件又會(huì)被組織在文件夾下,只要在文件夾下添加一個(gè)名為__init__.py的文件(init前后各有兩個(gè)下畫線,只要存在該文件就行,文件可以沒有內(nèi)容),該文件夾就成為包。由此可見,所謂模塊、包,其實(shí)都是對(duì)代碼的合理組織,目的是讓程序結(jié)構(gòu)更清晰,更好地復(fù)用代碼。而之前一直提到的庫(kù)則是一種通俗的稱謂,它強(qiáng)調(diào)的是一組有關(guān)聯(lián)的、可以廣為其他程序使用的代碼文件集合。庫(kù)既可以是模塊也可以是包,這取決于庫(kù)的規(guī)模。例如,random庫(kù)就是一個(gè)random.py代碼文件,因此random庫(kù)是一個(gè)模塊。而xml庫(kù)的代碼則分散在多個(gè)文件夾下的多個(gè)代碼文件中,因此xml庫(kù)是一個(gè)包。事實(shí)上在很多Python資料中,模塊、包與庫(kù)等這些概念往往混用,不會(huì)特意區(qū)別。本書之前也沒有刻意區(qū)別這些術(shù)語(yǔ)。9.1模塊與包的本質(zhì)這么看來(lái),在邏輯上一個(gè)Python程序可以由包、模塊、函數(shù)組成。包之下可以有子包或模塊,而模塊則是寫在同一個(gè)文件中的函數(shù)、類等的集合。在物理上,Python程序是一行行的代碼,這些代碼分散在一個(gè)個(gè)的文件中,這些文件又位于一個(gè)個(gè)的文件夾中,如圖9.1所示。圖9.1顯示的是xml庫(kù)的目錄結(jié)構(gòu)。從圖左側(cè)可知,xml庫(kù)下有dom、etree、parsers、sax等多個(gè)文件夾。圖左側(cè)選中了etree文件夾,右側(cè)可見有一個(gè)__init__.py文件。事實(shí)上這些文件夾下均有一個(gè)__init__.py文件,因此它們都是包。而etree包下還有多個(gè)Python代碼文件,它們都是模塊。每一個(gè)模塊中都有可被其他程序使用的函數(shù)、類等,如第4章解析XML格式數(shù)據(jù)用到的fromstring()函數(shù)就位于ElementTree.py模塊中。PART29.2庫(kù)的安裝與導(dǎo)入

9.2.1使用pip安裝第三方庫(kù)Python

中的庫(kù)通常分為以下幾類。(

1)內(nèi)置的。內(nèi)置庫(kù)通常是

Python

的核心模塊,隨著

Python解釋器一并安裝,因此不需要另外

安裝,可以直接導(dǎo)入使用。內(nèi)置庫(kù)又稱為

Python標(biāo)準(zhǔn)庫(kù)。(2)第三方的。經(jīng)過(guò)幾十年的發(fā)展,Python

擁有的庫(kù)非常多,不可能都與解釋器一并安裝。這

些庫(kù)經(jīng)過(guò)審核后可以被廣大

Python開發(fā)者使用,這種現(xiàn)成的但并未隨著解釋器內(nèi)置的庫(kù)被統(tǒng)稱為第

三方庫(kù)。使用它們時(shí)需要先安裝再導(dǎo)入。(3)自定義的。在大型系統(tǒng)的開發(fā)中,開發(fā)者往往將系統(tǒng)功能分為多個(gè)模塊來(lái)實(shí)現(xiàn),然后在主

模塊文件或其他代碼文件中導(dǎo)入使用其他功能的模塊。這些主要為自己的軟件程序服務(wù)的模塊就是

自定義的模塊。9.2.1使用pip安裝第三方庫(kù)內(nèi)置庫(kù)直接導(dǎo)入即可使用,但第三方庫(kù)是需要安裝的。Python

生態(tài)系統(tǒng)中有很多第三方庫(kù)具有

廣泛的應(yīng)用領(lǐng)域,如

NumPy、SciPy

等在科學(xué)計(jì)算、數(shù)據(jù)分析、人工智能等很多領(lǐng)域都有廣泛的應(yīng)

用。在第

5

章使用jieba庫(kù)時(shí)介紹了如何在

PyCharm

中安裝第三方庫(kù),但安裝第三方庫(kù)未必要依賴

PyCharm編程工具,更通用的方式是使用pip工具。高版本的

Python解釋器在安裝過(guò)程中默認(rèn)已經(jīng)

將pip

工具一并安裝了,所以可以直接在Windows

命令提示符窗口中使用pip

工具。下面以安裝

Pygame為例,演示如何使用pip安裝第三方庫(kù)。打開

Windows

的命令提示符窗口,在光標(biāo)后輸入“pip”,然后直接按

Enter鍵即可看到關(guān)于pip

工具的使用幫助。如果是要安裝工具包,如

Pygame,則只需輸入“pipinstallpygame”命令,按

Enter

鍵后

pip會(huì)自動(dòng)去網(wǎng)絡(luò)上下載指定的工具包并安裝,如圖

9.2所示。pip工具默認(rèn)是去國(guó)外的站點(diǎn)上

下載,如果速度過(guò)慢則可以更換為國(guó)內(nèi)的鏡像服務(wù)器,這方面的信息可以去搜索引擎進(jìn)行查詢。9.2.2導(dǎo)入模塊的不同形式庫(kù)只是一個(gè)形象的、通俗的稱謂,“導(dǎo)入庫(kù)”的真實(shí)含義是要復(fù)用該庫(kù)提供的某些代碼。而庫(kù)的代碼是位于模塊(代碼文件)中的,因此使用import語(yǔ)句導(dǎo)入庫(kù)時(shí)要指明導(dǎo)入的代碼文件,也就是模塊。1.導(dǎo)入整個(gè)模塊導(dǎo)入整個(gè)模塊是最基本的形式,即import<模塊名>。前面的例子中導(dǎo)入庫(kù)大多使用的是這種形式。以這種形式導(dǎo)入后,使用模塊中的函數(shù)、類等內(nèi)容時(shí)都要添加模塊名前綴。但由于庫(kù)的規(guī)模不同,有的庫(kù)本身只是一個(gè)模塊,如random庫(kù)、math庫(kù)等,導(dǎo)入就很簡(jiǎn)單;有的庫(kù)有多個(gè)模塊,如xml庫(kù)。對(duì)于xml這類有多個(gè)模塊的庫(kù),導(dǎo)入時(shí)不能簡(jiǎn)單地書寫庫(kù)名,因?yàn)檎嬲獙?dǎo)入的是模塊,所以必須說(shuō)明要導(dǎo)入xml庫(kù)中的哪個(gè)模塊。一般這種情形下模塊都會(huì)位于包(文件夾)下,因此在導(dǎo)入模塊時(shí)必然涉及文件夾路徑。只是import語(yǔ)句中會(huì)將路徑分隔符改為點(diǎn),于是就有下面代碼9.1的寫法,這也是在第4章出現(xiàn)過(guò)的寫法,現(xiàn)在應(yīng)該理解得更清楚了。9.2.2導(dǎo)入模塊的不同形式代碼

9.1

導(dǎo)入整個(gè)模塊

9.2.2導(dǎo)入模塊的不同形式代碼

9.1

導(dǎo)入整個(gè)模塊

代碼中的random

模塊導(dǎo)入時(shí)直接書寫模塊對(duì)應(yīng)的代碼文件名,注意不用寫文件的擴(kuò)展名。而

xml庫(kù)的

ElementTree.py模塊在

xml\etree\文件夾下,因此導(dǎo)入時(shí)將路徑分隔符改為點(diǎn),同樣不用寫

文件擴(kuò)展名。當(dāng)然,無(wú)論模塊文件所處的路徑深淺,這種將整個(gè)模塊導(dǎo)入的形式要求在使用模塊中

的函數(shù)等屬性時(shí)必須添加模塊前綴,所以

choice()函數(shù)及

fromstring()函數(shù)在使用時(shí)都必須有前綴名。

xml.etree.ElementTree作為前綴確實(shí)過(guò)長(zhǎng),書寫不便,所以

import語(yǔ)句可以使用

as關(guān)鍵字給導(dǎo)入

的模塊起別名,這樣只需寫

ET.fromstring()即可,較為方便。另外,程序要導(dǎo)入多個(gè)模塊時(shí),理論上可以使用一個(gè)

import

語(yǔ)句,模塊名使用逗號(hào)分隔。但Python

不建議使用一行

import導(dǎo)入多個(gè)模塊,推薦使用多個(gè)

import語(yǔ)句,每行導(dǎo)入一個(gè)模塊。9.2.2導(dǎo)入模塊的不同形式代碼

9.1

導(dǎo)入整個(gè)模塊

2.導(dǎo)入模塊的某個(gè)屬性如果只是需要使用模塊中的一兩個(gè)屬性,不想將該模塊中的其他內(nèi)容都導(dǎo)入自己的代碼文件的作用域中,因?yàn)槟菢涌赡軙?huì)讓自己的程序變得臃腫。針對(duì)這種情形可以使用如代碼9.2所示的形式來(lái)直接導(dǎo)入目標(biāo)屬性。相對(duì)于傳統(tǒng)的import形式,代碼9.2所示的形式是使用什么只導(dǎo)入什么,更有針對(duì)性。但如果要使用模塊中較多的屬性內(nèi)容,這種方式就不適合了。9.2.2導(dǎo)入模塊的不同形式代碼

9.1

導(dǎo)入整個(gè)模塊

代碼9.2導(dǎo)入模塊中的個(gè)別屬性fromrandomimportchoice#僅導(dǎo)入模塊中要使用的函數(shù)fromxml.etree.ElementTreeimportfromstringxml_str="""<data><entryauthor="孔子">學(xué)而時(shí)習(xí)之,不亦說(shuō)乎?</entry><entryauthor="子夏">日知其所亡,月無(wú)忘其所能,可謂好學(xué)也已矣。</entry><entryauthor="顧炎武">有一日未死之身,則有一日未聞之道。</entry></data>"""root=fromstring(xml_str)#直接書寫函數(shù)名,沒有前綴data_base=[]forentryinroot:author=entry.attrib["author"]content=entry.textdata_base.append((author,content))entry_selected=choice(data_base)#沒有前綴print(entry_selected)9.2.2導(dǎo)入模塊的不同形式代碼

9.1

導(dǎo)入整個(gè)模塊

使用from直接導(dǎo)入模塊中的目標(biāo)屬性后,使用它們時(shí)無(wú)須書寫模塊前綴。這一點(diǎn)既有優(yōu)點(diǎn)也有弊端。優(yōu)點(diǎn)是書寫簡(jiǎn)潔、方便;弊端是在導(dǎo)入多個(gè)模塊時(shí),因?yàn)闆]有模塊前綴,所以不知道哪個(gè)函數(shù)來(lái)自哪個(gè)模塊,不同模塊的同名函數(shù)會(huì)發(fā)生名稱沖突,為程序引入了不必要的混亂因素。PART39.3Python生態(tài)系統(tǒng)之Pygame庫(kù)9.3Python生態(tài)系統(tǒng)之Pygame庫(kù)代碼

9.1

導(dǎo)入整個(gè)模塊

Pygame庫(kù)是Python生態(tài)系統(tǒng)中比較有名的用來(lái)開發(fā)游戲的庫(kù),它提供了易用的、豐富的音頻、視頻操作功能,非常適合用來(lái)開發(fā)小型游戲。實(shí)際上,動(dòng)手編寫游戲是一個(gè)非常好的學(xué)習(xí)編程的途徑,學(xué)習(xí)編寫游戲可能比玩游戲更有意思。9.3.1初識(shí)Pygame代碼

9.1

導(dǎo)入整個(gè)模塊

Pygame庫(kù)中有很多模塊,分別負(fù)責(zé)游戲開發(fā)中的各類任務(wù)。例如,pygame.display負(fù)責(zé)處理界面顯示方面的操作,pygame.time負(fù)責(zé)和時(shí)間有關(guān)的操作,pygame.mixer可以處理音頻。其中,pygame.display下的set_mode()函數(shù)用來(lái)創(chuàng)建游戲的主界面,這個(gè)函數(shù)會(huì)返回一個(gè)Surface對(duì)象,代表著游戲主界面。Surface對(duì)象有一個(gè)blit()方法,可以將游戲形象(Pygame稱為精靈)“繪制”在需要的位置。游戲一般有一些精心設(shè)計(jì)的游戲形象,Pygame將這些游戲形象稱為精靈(sprite)。精靈可能是任何東西,可以是拿著武器沖鋒陷陣的戰(zhàn)士,也可以是被動(dòng)挨打的無(wú)生命的乒乓球,又或者是戰(zhàn)士手中的槍、用來(lái)打球的球拍等,這些都可以看成游戲形象,都可以被稱為精靈。游戲就是按照預(yù)設(shè)的邏輯讓這些精靈不斷變化,形成不同的游戲局面,讓玩家沉浸其中,得到樂(lè)趣。9.3.1初識(shí)Pygame代碼

9.1

導(dǎo)入整個(gè)模塊

游戲過(guò)程有兩面,一面是玩家看到的屏幕上五光十色的游戲角色在運(yùn)動(dòng)、動(dòng)作、產(chǎn)生、消亡。這些精靈們有各自的外觀形象,它們?cè)谄聊簧系幕顒?dòng)也是連續(xù)的,真的好像有生命一樣。但這一切都是假象,精靈的形象不過(guò)是一些圖片,精靈不同的狀態(tài)對(duì)應(yīng)不同的圖片,這些圖片可以根據(jù)游戲需要出現(xiàn)在指定位置。游戲的另一面才是其真容:沒有動(dòng)作,更不連續(xù),一切都是數(shù)據(jù)的變化。所有的精靈都只是一組數(shù)據(jù),數(shù)據(jù)的改變意味著精靈出現(xiàn)了某種變化。游戲只是記錄每個(gè)精靈下一刻的數(shù)據(jù)狀態(tài),然后根據(jù)這些數(shù)據(jù)將對(duì)應(yīng)的精靈形象(圖片)在恰當(dāng)?shù)臅r(shí)間“繪制”在屏幕恰當(dāng)?shù)奈恢?。因?yàn)楫嬅娓滤俣确浅?欤谌丝磥?lái)畫面是連續(xù)的。所以游戲開發(fā)除設(shè)計(jì)好各色精靈的外觀形象外,更重要的其實(shí)還是看不見的各種數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì),使用什么樣的數(shù)據(jù)結(jié)構(gòu)記錄維護(hù)游戲精靈的狀態(tài),使用什么樣的算法去改變數(shù)據(jù)狀態(tài)是游戲內(nèi)在的靈魂。接下來(lái)通過(guò)一個(gè)簡(jiǎn)單的小例子來(lái)練習(xí)使用Pygame開發(fā)游戲。9.3.2搭建游戲主框架代碼

9.1

導(dǎo)入整個(gè)模塊

游戲過(guò)程有兩面,一面是玩家看到的屏幕上五光十色的游戲角色在運(yùn)動(dòng)、動(dòng)作、產(chǎn)生、消亡。這些精靈們有各自的外觀形象,它們?cè)谄聊簧系幕顒?dòng)也是連續(xù)的,真的好像有生命一樣。但這一切都是假象,精靈的形象不過(guò)是一些圖片,精靈不同的狀態(tài)對(duì)應(yīng)不同的圖片,這些圖片可以根據(jù)游戲需要出現(xiàn)在指定位置。游戲的另一面才是其真容:沒有動(dòng)作,更不連續(xù),一切都是數(shù)據(jù)的變化。所有的精靈都只是一組數(shù)據(jù),數(shù)據(jù)的改變意味著精靈出現(xiàn)了某種變化。游戲只是記錄每個(gè)精靈下一刻的數(shù)據(jù)狀態(tài),然后根據(jù)這些數(shù)據(jù)將對(duì)應(yīng)的精靈形象(圖片)在恰當(dāng)?shù)臅r(shí)間“繪制”在屏幕恰當(dāng)?shù)奈恢谩R驗(yàn)楫嬅娓滤俣确浅??,在人看?lái)畫面是連續(xù)的。所以游戲開發(fā)除設(shè)計(jì)好各色精靈的外觀形象外,更重要的其實(shí)還是看不見的各種數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì),使用什么樣的數(shù)據(jù)結(jié)構(gòu)記錄維護(hù)游戲精靈的狀態(tài),使用什么樣的算法去改變數(shù)據(jù)狀態(tài)是游戲內(nèi)在的靈魂。接下來(lái)通過(guò)一個(gè)簡(jiǎn)單的小例子來(lái)練習(xí)使用Pygame開發(fā)游戲。9.3.2搭建游戲主框架代碼

9.1

導(dǎo)入整個(gè)模塊

Pygame庫(kù)中有多個(gè)模塊,可根據(jù)需要導(dǎo)入所需的模塊。其中,pygame.locals模塊定義了Pygame中預(yù)置的常量,如標(biāo)志窗體退出事件的常量QUIT。另外,在游戲窗體退出后,整個(gè)程序的運(yùn)行也要終止,所以這里還需要用到sys庫(kù)中的exit()函數(shù),如代碼9.3所示。9.3.2搭建游戲主框架代碼

9.1

導(dǎo)入整個(gè)模塊

代碼9.3搭建游戲主框架importPygamefrompygame.localsimportQUITimportsyspygame.init()#初始化

Pygamesurface=pygame.display.set_mode((640,480))#游戲窗體大小pygame.display.set_caption('Hello,Pygame!')#窗體標(biāo)題whileTrue:#主循環(huán)foreventinpygame.event.get():#獲取發(fā)生的事件ifevent.type==QUIT:#如果有退出事件pygame.quit()#Pygame退出sys.exit()#程序停止執(zhí)行pygame.display.update()#刷新畫面9.3.2搭建游戲主框架代碼

9.1

導(dǎo)入整個(gè)模塊

運(yùn)行這段代碼可以看到一個(gè)指定尺寸的Pygame窗體,其標(biāo)題欄為指定的文字內(nèi)容,單擊窗口右上角的“關(guān)閉”按鈕結(jié)束程序,如圖9.3所示。9.3.2搭建游戲主框架代碼

9.1

導(dǎo)入整個(gè)模塊

這段程序只是一個(gè)基本的框架,并沒有什么具體的游戲情節(jié),但還是有幾個(gè)重要的信息。首先是對(duì)Pygame各模塊進(jìn)行初始化,然后在調(diào)用display模塊的set_mode()函數(shù)產(chǎn)生主窗體界面時(shí)可以指定窗口尺寸。如果長(zhǎng)寬尺寸都為0,則產(chǎn)生一個(gè)和屏幕一樣大小的窗體。程序?qū)et_mode()函數(shù)返回的代表窗體界面的Surface對(duì)象保存在一個(gè)變量中,以便在游戲細(xì)節(jié)中使用。接下來(lái)調(diào)用了display.set_caption()函數(shù)設(shè)置窗體標(biāo)題欄信息。這里并沒有指明要設(shè)置的是哪一個(gè)Surface窗口,因?yàn)镻ygame同一時(shí)間只有一個(gè)Surface對(duì)象是當(dāng)前窗口,因此無(wú)須說(shuō)明。再往下就是重點(diǎn)了,這里有個(gè)條件為True的循環(huán),不妨稱其為游戲的主循環(huán)。程序運(yùn)行后該循環(huán)會(huì)不停地執(zhí)行。游戲進(jìn)行時(shí)需要不停地刷新畫面,因此完成游戲刷新的代碼應(yīng)該寫在這個(gè)循環(huán)中。9.3.2搭建游戲主框架代碼

9.1

導(dǎo)入整個(gè)模塊

當(dāng)然循環(huán)不能成為死循環(huán),打破這個(gè)循環(huán)的是玩家關(guān)閉窗口事件。事實(shí)上游戲進(jìn)行中可能發(fā)生很多事件(event),如窗口關(guān)閉事件、單擊鼠標(biāo)事件、鼠標(biāo)指針移動(dòng)事件、鍵盤上的按鍵事件等。每個(gè)事件都有一個(gè)編號(hào),如退出事件的編號(hào)為256。但使用編號(hào)不友好,故Pygame為這些事件都定義了名稱;如退出事件記為QUIT,又因其值不變,故一般稱為常量。發(fā)生的事件會(huì)被送到一個(gè)事件隊(duì)列中。通過(guò)調(diào)用pygame.event.get()函數(shù)可以獲取當(dāng)前事件隊(duì)列中的所有事件,代碼遍歷發(fā)生的事件,看看其中有沒有退出事件(QUIT),如果有則退出游戲。退出時(shí)首先要退出Pygame,然后調(diào)用sys.exit()退出Python系統(tǒng)。程序循環(huán)中的最后一句update()負(fù)責(zé)把緩存中的畫面數(shù)據(jù)真正送到屏幕上,不斷更新界面顯示。9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

下面在游戲框架代碼的基礎(chǔ)上來(lái)真正做點(diǎn)什么,如讓一個(gè)卡通橘子臉在屏幕上不斷地變換兩種表情,而且還能跟隨方向鍵移動(dòng)。要完成這個(gè)場(chǎng)景首先要預(yù)備好兩個(gè)橘子臉圖片,一個(gè)高興的表情,一個(gè)悲傷的表情。有了這樣兩個(gè)圖片,只需快速交替顯示它們就可以出現(xiàn)變臉的效果。而跟隨方向鍵移動(dòng)時(shí)需要知道玩家按下了哪個(gè)鍵,并根據(jù)按鍵方向更新橘子臉的位置數(shù)據(jù),再根據(jù)最新位置數(shù)據(jù)在界面上重新繪制出橘子臉,這樣橘子臉就可以移動(dòng)了。當(dāng)然繪制前還要確認(rèn)應(yīng)該使用兩個(gè)表情中的哪一個(gè)。這就是整個(gè)代碼要完成的主要工作。接下來(lái)將對(duì)代碼的分析分成兩大部分,while主循環(huán)之前的預(yù)備工作,以及while主循環(huán)內(nèi)部要負(fù)責(zé)的工作。9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

1.預(yù)備工作階段除設(shè)置游戲窗體的大小、標(biāo)題等常規(guī)任務(wù)外,預(yù)備工作階段最重要的任務(wù)是將兩個(gè)不同表情的橘子臉圖片讀入內(nèi)存,使用pygame.image.load()函數(shù)完成這個(gè)工作。因?yàn)橛袃蓚€(gè)圖片,為了訪問(wèn)方便,將兩個(gè)圖片載入后保存在一個(gè)列表中。load()函數(shù)載入圖片后返回的也是一個(gè)Surface對(duì)象。也就是說(shuō),不論是窗體界面,還是代表游戲精靈的圖片,在Pygame看來(lái)都是Surface對(duì)象。因?yàn)樗鼈兌际怯螒蛲獗淼囊粚悠?,真正的游戲精靈是由無(wú)形的、看不見的數(shù)據(jù)來(lái)表示的。因此接下來(lái)需要一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)表示真正的橘子臉精靈,這里選擇了Pygame提供的Rect類。顧名思義,這個(gè)類可以表示一個(gè)矩形,而橘子臉精靈顯然可以概括為一個(gè)矩形,由兩部分共同組成,看不見的Rect對(duì)象和看得見的表情圖片。Rect對(duì)象保存了橘子臉精靈的狀態(tài)數(shù)據(jù),表情圖片出現(xiàn)在游戲窗體的什么位置完全由Rect對(duì)象的數(shù)據(jù)決定,表情圖片只是外在的一層皮。9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

明白了大概任務(wù),再來(lái)研讀預(yù)備工作的代碼就好理解了,細(xì)節(jié)如代碼9.4所示。與上一段游戲的大框架代碼相比,這里多導(dǎo)入了幾個(gè)locals模塊下的常量,如K_RIGHT等按鍵事件,主要用來(lái)實(shí)現(xiàn)橘子臉跟隨方向鍵移動(dòng)。代碼9.4橘子臉游戲的預(yù)備階段importPygamefrompygame.localsimportQUIT,K_RIGHT,K_LEFT,K_UP,K_DOWNimportsys#預(yù)備工作pygame.init()WINDOW_WID,WINDOW_HEI=(640,480)surface=pygame.display.set_mode((WINDOW_WID,WINDOW_HEI))pygame.display.set_caption('Orangeface...')imgs=[]#保存橘子臉圖片的列表foriinrange(2):img=pygame.image.load('file\\Orange-'+str(i)+'.png')imgs.append(img)9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

代碼9.4橘子臉游戲的預(yù)備階段img_rect=pygame.Rect(0,0,32,32)face_change_limit=2000face_change_step=3face_id=0move_speed=1background=(255,255,255)#代表橘子臉的數(shù)據(jù)結(jié)構(gòu)#當(dāng)face_change_limit按照f(shuō)ace_change_step#的速度減為0時(shí)橘子臉會(huì)變換表情#按鍵移動(dòng)的速度#背景色9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

在代碼文件所在位置的file文件夾下預(yù)備好兩個(gè)32像素×32像素的不同表情的圖片,為了方便,兩個(gè)圖片命名為Orange-0.png和Orange-1.png,這樣pygame.image.load()函數(shù)即可將它們載入。這兩個(gè)圖片被保存在imgs列表中,因此可以通過(guò)imgs[0]和imgs[1]訪問(wèn)。有了橘子精靈的外在形象,還要有代表橘子精靈的內(nèi)在數(shù)據(jù)結(jié)構(gòu),因此通過(guò)Rect類定義一個(gè)矩形對(duì)象img_rect,它保存了矩形的左上角坐標(biāo)及長(zhǎng)寬共4項(xiàng)數(shù)據(jù)。img_rect對(duì)象會(huì)時(shí)刻記錄橘子精靈的位置,游戲一開始,橘子精靈出現(xiàn)在窗體的左上角,因此橫縱坐標(biāo)都為0,長(zhǎng)寬均為32像素,這是由圖片的尺寸決定的。后面在游戲的主循環(huán)結(jié)構(gòu)中會(huì)根據(jù)玩家按下不同的方向鍵來(lái)不斷更新img_rect的數(shù)據(jù),再根據(jù)img_rect不斷地繪制橘子精靈的外在圖片就可以實(shí)現(xiàn)移動(dòng)效果了。9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

再接下來(lái)的幾行代碼初看似乎不易理解,其實(shí)也是完成一些循環(huán)之前的必要數(shù)據(jù)準(zhǔn)備工作。因?yàn)殚僮泳`不僅可以跟隨方向鍵移動(dòng),還在不停地變化表情。這就要求定期地更換顯示的表情圖片,一會(huì)兒是imgs[0],一會(huì)兒是imgs[1]。那么多長(zhǎng)時(shí)間更換表情呢?這由兩個(gè)變量face_change_limit與face_change_step共同決定,變量face_change_limit每次減少face_change_step,當(dāng)face_change_limit小于等于0時(shí),就意味著該更換表情圖片了。因此在face_change_limit值一定的情況下,face_change_step的值越大,換表情的頻率就越快。變量move_speed定義了橘子精靈的移動(dòng)速度,其實(shí)就是每次根據(jù)按鍵移動(dòng)位置時(shí),img_rect對(duì)象的坐標(biāo)改變多少。改變得越大,一次按鍵移動(dòng)的距離就越大。代碼的最后按照RGB顏色模型給出白色,這個(gè)顏色將被設(shè)置為游戲窗體的背景色。所有這些預(yù)備的變量都會(huì)在游戲主循環(huán)中用到,所以接下來(lái)看看主循環(huán)內(nèi)是如何利用這些變量實(shí)現(xiàn)預(yù)期效果的。9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

2.主循環(huán)階段游戲主循環(huán)的代碼實(shí)現(xiàn)如代碼9.5所示。在循環(huán)結(jié)構(gòu)中,首先通過(guò)surface.fill()方法將界面背景“填充”為指定顏色。每次循環(huán)都會(huì)執(zhí)行這行代碼,這意味著主窗口界面會(huì)不斷地被“填充”,之前界面上的畫面內(nèi)容就被白色覆蓋掉了,好比一面墻被重新粉刷,原來(lái)墻上的圖案就都不見了。因此橘子臉要重新繪制,每次繪制時(shí)都要判斷使用哪個(gè)表情圖片,是imgs[0]還是imgs[1]。這里就用到了face_change_limit與face_change_step兩個(gè)變量。face_change_limit每次循環(huán)會(huì)減少face_change_step,當(dāng)face_change_limit由初始值2000降到小于等于0時(shí),換表情的動(dòng)作就該發(fā)生了。因此讓face_id加1,如果face_id原來(lái)是0,則現(xiàn)在為1;如果原來(lái)為1,則現(xiàn)在為2。之后將face_id除以2的余數(shù)賦給face_id本身??梢钥闯鼋?jīng)過(guò)這樣處理后,face_id的取值會(huì)在0和1之間交替變換,程序就是根據(jù)face_id去imgs列表中提取相應(yīng)的表情的。因?yàn)閷?duì)face_id值的處理并不是每次循環(huán)都發(fā)生,而是要face_change_limit從初始值減到0才發(fā)生一次。因此變量face_change_limit與face_change_step就控制了表情更替的速度,讀者可以在預(yù)備階段將face_change_step的值調(diào)大來(lái)試試效果。9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

代碼9.5橘子臉游戲的主循環(huán)階段whileTrue:foreventinpygame.event.get():ifevent.type==QUIT:pygame.quit()sys.exit()surface.fill(background)#重填窗體背景face_change_limit-=face_change_stepifface_change_limit<=0:#換臉發(fā)生face_change_limit=2000face_id+=1face_id%=29.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

代碼9.5橘子臉游戲的主循環(huán)階段surface.blit(imgs[face_id],img_rect)#根據(jù)最新位置繪制橘子臉#根據(jù)按鍵移動(dòng)橘子臉

keys=pygame.key.get_pressed()#獲取被按下的鍵ifkeys[K_RIGHT]:

img_rect.x+=move_speed

ifkeys[K_LEFT]:

img_rect.x-=move_speed

ifkeys[K_UP]:

img_rect.y-=move_speed

ifkeys[K_DOWN]:

img_rect.y+=move_speed

#防止橘子臉移出窗體9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

代碼9.5橘子臉游戲的主循環(huán)階段ifimg_rect.x<0:img_rect.x=0ifimg_rect.x>WINDOW_WID-32:img_rect.x=WINDOW_WID-32ifimg_rect.y<0:img_rect.y=0ifimg_rect.y>WINDOW_HEI-32:img_rect.y=WINDOW_HEI-32pygame.display.update()9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

決定了使用的表情圖片,接下來(lái)的工作就是將表情圖片繪制在img_rect指定的位置。這是通過(guò)主窗口對(duì)象的blit()方法完成的,這個(gè)方法可以將游戲精靈的外在形象貼在窗體的指定位置。而img_rect對(duì)象記錄的位置是可以隨玩家操作方向鍵而變化的,循環(huán)內(nèi)接下來(lái)的代碼就是實(shí)現(xiàn)這個(gè)工作的。Pygame的key模塊下的get_pressed()函數(shù)可以獲知玩家按下了什么鍵。在該函數(shù)的返回結(jié)果中查看4個(gè)方向鍵是否被按下,并相應(yīng)更新img_rect對(duì)象左上角的坐標(biāo)。例如,如果玩家按下了向右的方向鍵,則keys[K_RIGHT]為真,因此img_rect的橫坐標(biāo)增大,增大多少由move_speed決定,所以move_speed控制橘子臉的移動(dòng)速度。最后還有一個(gè)問(wèn)題需要考慮,橘子臉不能移到游戲窗口之外,因此每輪循環(huán)都要判斷img_rect中橫縱坐標(biāo)的上下限。到此程序的邏輯就都實(shí)現(xiàn)了,將代碼9.4與代碼9.5合在一起運(yùn)行,調(diào)整預(yù)備階段的一些變量值,觀察橘子臉的移動(dòng)速度、換臉頻率等效果,可以加深對(duì)代碼的理解。如圖9.4所示是代碼運(yùn)行后的結(jié)果。9.3.3完善游戲細(xì)節(jié)代碼

9.1

導(dǎo)入整個(gè)模塊

決定了使用的表情圖片,接下來(lái)的工作就是將表情圖片繪制在img_rect指定的位置。這是通過(guò)主窗口對(duì)象的blit()方法完成的,這個(gè)方法可以將游戲精靈的外在形象貼在窗體的指定位置。而img_rect對(duì)象記錄的位置是可以隨玩家操作方向鍵而變化的,循環(huán)內(nèi)接下來(lái)的代碼就是實(shí)現(xiàn)這個(gè)工作的。Pygame的key模塊下的get_pressed()函數(shù)可以獲知玩家按下了什么鍵。在該函數(shù)的返回結(jié)果中查看4個(gè)方向鍵是否被按下,并相應(yīng)更新img_rect對(duì)象左上角的坐標(biāo)。例如,如果玩家按下了向右的方向鍵,則keys[K_RIGHT]為真,因此img_rect的橫坐標(biāo)增大,增大多少由move_speed決定,所以move_speed控制橘子臉的移動(dòng)速度。最后還有一個(gè)問(wèn)題需要考慮,橘子臉不能移到游戲窗口之外,因此每輪循環(huán)都要判斷img_rect中橫縱坐標(biāo)的上下限。到此程序的邏輯就都實(shí)現(xiàn)了,將代碼9.4與代碼9.5合在一起運(yùn)行,調(diào)整預(yù)備階段的一些變量值,觀察橘子臉的移動(dòng)速度、換臉頻率等效果,可以加深對(duì)代碼的理解。如圖9.4所示是代碼運(yùn)行后的結(jié)果。PART49.4小試牛刀9.4小試牛刀前面介紹了使用Pygame開發(fā)小游戲的基本流程,接下來(lái)在小試牛刀環(huán)節(jié)開發(fā)一款可玩性更強(qiáng)的小游戲。游戲中有一個(gè)小球在窗口中“游蕩”,玩家通過(guò)左右移動(dòng)鼠標(biāo)指針控制一個(gè)擋板,任務(wù)是不讓小球掉落到窗口下沿。隨著玩家擊打小球次數(shù)的增多,小球的移動(dòng)速度會(huì)越來(lái)越快,游戲難度越來(lái)越高。當(dāng)小球掉落游戲結(jié)束時(shí),窗口中顯示玩家的擊球次數(shù)。如果玩家愿意,則單擊開始新的一局。游戲運(yùn)行的效果如圖9.5所示。9.4.1游戲預(yù)備工作游戲需要準(zhǔn)備小球與擋板的圖片素材,這個(gè)例子中使用的小球圖片有8像素,擋板的寬度為55像素。游戲代碼假設(shè)這些圖片素材位于file文件夾下。整個(gè)程序仍然分為主循環(huán)之前的預(yù)備工作和while主循環(huán)兩部分,先來(lái)看預(yù)備工作階段,細(xì)節(jié)如代碼9.6所示。代碼被空行分成幾個(gè)小段落,后面會(huì)詳細(xì)解釋。(代碼見書213頁(yè)9.6)9.4.2游戲主循環(huán)所有預(yù)備工作做完后,接下來(lái)是在while循環(huán)中不斷更新的工作。這些工作構(gòu)成了代碼9.7,循環(huán)內(nèi)的代碼也被空行分成了幾個(gè)段落,下面進(jìn)行逐一分析。(代碼見書215頁(yè)9.7)PART59.5拓展實(shí)踐:使用模塊組織代碼當(dāng)程序稍具規(guī)模后,可以根據(jù)功能將代碼分布在多個(gè)文件中,每個(gè)代碼文件就是一個(gè)模塊。程序由多個(gè)模塊組成,必然會(huì)出現(xiàn)在某個(gè)模塊中導(dǎo)入其他自定義模塊的情形。接下來(lái)就以一個(gè)具體的例子演練如何使用模塊組織代碼。9.5拓展實(shí)踐:使用模塊組織代碼在人類的民主活動(dòng)中投票是一個(gè)重要的形式。常用的投票形式往往是選民人手一票,每個(gè)人將自己的一票投給自己支持的候選人,獲得票數(shù)多的候選人勝出。除此以外有沒有其他的投票模式呢?1770年,法國(guó)舉辦了一場(chǎng)選舉,選舉規(guī)則是每一個(gè)選民擁有一張選票,并按對(duì)每位候選人的認(rèn)可程度,在選票上給所有候選人進(jìn)行排序。作為選票結(jié)果的統(tǒng)計(jì)者,數(shù)學(xué)家波達(dá)設(shè)想的方法是將選票上的位次轉(zhuǎn)換為分值,這樣可把每一張選票上的候選人排名名次轉(zhuǎn)換成一串相應(yīng)的數(shù)字。例如,在有4個(gè)候選人的選舉中,排在第1名的候選人因?yàn)閾魯×?個(gè)人所以得3分。同理第2名得2分,第3名得1分,第4名得0分。然后把所有選票上每個(gè)候選人各自得到的分?jǐn)?shù)全部加在一起,最后累計(jì)得分最高者獲勝。這種方法被命名為波達(dá)計(jì)數(shù)法(Bordacount)。9.5.1多樣的投票模式再來(lái)看看同一時(shí)期的另一位法國(guó)數(shù)學(xué)家孔多塞(Condorcet)提出的一種計(jì)票方式。每個(gè)候選人都要和其他候選人進(jìn)行兩兩的對(duì)決。在兩人對(duì)決時(shí),每一票都屬于排名靠前的候選人,最終獲得選票多的人在兩人對(duì)決中勝出。只有在兩兩對(duì)決的過(guò)程中戰(zhàn)勝所有其他候選人的才是最終獲勝者。孔多塞計(jì)票法可以選出被大多數(shù)人擁護(hù)的選舉人,但也有可能因?yàn)闆]人能戰(zhàn)勝所有其他人,從而導(dǎo)致沒有獲勝者。9.5.1多樣的投票模式假設(shè)有4位候選人,名字分別為A、B、C、D。關(guān)于這場(chǎng)選舉的投票數(shù)據(jù)被保存在一個(gè)文本文件中,文件的每一行代表一個(gè)投票人的投票結(jié)果。這個(gè)結(jié)果是投票人對(duì)4位候選人的一個(gè)排位順序,使用空格分隔,如下(數(shù)據(jù)有刪減)。9.5.2一個(gè)具體的投票問(wèn)題下面按照多數(shù)計(jì)票法、波達(dá)計(jì)票法和孔多塞計(jì)票法3種投票方式來(lái)對(duì)同一個(gè)投票問(wèn)題進(jìn)行處理,看看結(jié)果有何不同??梢钥闯觯瑹o(wú)論使用何種計(jì)票方法,整個(gè)計(jì)票的工作大致如下:首先,讀入投票數(shù)據(jù)。其次,匯總投票數(shù)據(jù)。根據(jù)不同計(jì)票方法,匯總過(guò)程不盡相同。例如,對(duì)于多數(shù)計(jì)票法,每個(gè)選民的投票只有排在第一順位的候選人有效,而波達(dá)計(jì)票法則要將每個(gè)選民的排位換算為相應(yīng)的分?jǐn)?shù)??锥嗳?jì)票法則關(guān)注候選人兩兩對(duì)決的勝負(fù)。無(wú)論采用哪種計(jì)票方法,最后都要根據(jù)匯總結(jié)果,給出選舉結(jié)論。因此計(jì)票工作可以分成幾個(gè)函數(shù)來(lái)完成。(1)負(fù)責(zé)讀入投票數(shù)據(jù)的read_vote_data()函數(shù)。(2)按照不同計(jì)票方法進(jìn)行匯總的幾個(gè)函數(shù)。(3)根據(jù)匯總結(jié)果給出選舉結(jié)論的give_vote_result()函數(shù)。這些函數(shù)可以被分在不同的模塊中,按照不同計(jì)票方式進(jìn)行匯總的函數(shù)可以統(tǒng)一放在一個(gè)模塊中,這個(gè)模塊文件可以命名為vote_methods.py。而read_vote_data()函數(shù)和give_vote_result()函數(shù)可以放在同一個(gè)模塊中,可以命名為vote_tools.py。主程序則寫在第三個(gè)代碼文件中,這樣整個(gè)程序被分為3個(gè)模塊,主程序所在的模塊需要導(dǎo)入另外兩個(gè)模塊。為了演示方便,這里假設(shè)所有的代碼文件都在同一個(gè)目錄下。9.5.2一個(gè)具體的投票問(wèn)題先來(lái)看vote_tools模塊。這個(gè)模塊下有兩個(gè)函數(shù),分別是讀入選舉數(shù)據(jù)的read_vote_data()函數(shù)和根據(jù)計(jì)票匯總結(jié)果給出選舉結(jié)論的give_vote_result()函數(shù)。read_vote_data()函數(shù)的細(xì)節(jié)如代碼9.8所示。這個(gè)函數(shù)需要知道保存投票數(shù)據(jù)的文件名,而其返回值則是一個(gè)嵌套的列表,該列表的每一個(gè)元素是原數(shù)據(jù)文件中的一行按照空格拆分后的列表。代碼9.8模塊vote_tools中負(fù)責(zé)讀取數(shù)據(jù)的函數(shù)defread_vote_data(vote_file):"""讀取投票數(shù)據(jù)的函數(shù)參數(shù)vote_file:文件名9.5.3模塊vote_tools代碼9.8模塊vote_tools中負(fù)責(zé)讀取數(shù)據(jù)的函數(shù)返回值:嵌套列表"""vote_data=[]withopen(vote_file,"r")asf:forlineinf:one_vote=line.split()#按空格拆分vote_data.append(one_vote)returnvote_data9.5.3模塊vote_toolsgive_vote_result()函數(shù)的細(xì)節(jié)如代碼9.9所示。這個(gè)函數(shù)需要拿到匯總的結(jié)果aggregate_dic,這是一個(gè)字典,記錄了每個(gè)候選人的得票情況,或者是得分,又或者是該候選人戰(zhàn)勝的對(duì)手?jǐn)?shù)量。也就是說(shuō)盡管有多種計(jì)票方式,但每種計(jì)票方式最后匯總的結(jié)果都是一個(gè)字典,該字典會(huì)傳遞給give_vote_result()函數(shù)。因?yàn)榭锥嗳?jì)票法的規(guī)則導(dǎo)致其有可能沒有獲勝者,所以處理細(xì)節(jié)略有不同。give_vote_result()函數(shù)還有一個(gè)參數(shù),用來(lái)判斷當(dāng)前使用的計(jì)票方式是否為孔多塞計(jì)票法,該參數(shù)的默認(rèn)值為假。give_vote_result()函數(shù)的返回值有兩項(xiàng),一項(xiàng)是記錄最終獲勝候選人的列表winner,另一項(xiàng)是這些勝者的得票或得分情況。如果是孔多塞計(jì)票法,則winner有可能為空。9.5.3模塊vote_tools代碼9.9模塊vote_tools中負(fù)責(zé)給出選舉結(jié)論的函數(shù)defgive_vote_result(aggregate_dic,condorcet=False):"""根據(jù)匯總結(jié)果,給出最終投票結(jié)論"""winner=[]ifcondorcet:highest_vote=len(aggregate_dic)–1#戰(zhàn)勝所有其他候選人forcandidateinaggregate_dic.keys():ifaggregate_dic[candidate]==highest_vote:winner.append(candidate)break9.5.3模塊vote_tools代碼9.9模塊vote_tools中負(fù)責(zé)給出選舉結(jié)論的函數(shù)else:highest_vote=0forcandidateinaggregate_dic:#出現(xiàn)一個(gè)候選人比之前所有人的票數(shù)都高ifaggregate_dic[candidate]>highest_vote:winner.clear()winner.append(candidate)highest_vote=aggregate_dic[candidate]elifaggregate_di

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論