鍍金池/ 教程/ Python/ exercise50.你的第一個(gè)網(wǎng)站
附錄 A-練習(xí) 9:生成一個(gè)空文件(Touch, New-Item)
附錄 A-練習(xí) 10:復(fù)制文件 (cp)
exercise44.繼承 Vs.包含
附錄 A-練習(xí) 14:刪除文件 (rm)
附錄 A-練習(xí) 11:移動(dòng)文件 (mv)
exercise46.項(xiàng)目骨架
附錄 A-練習(xí) 3:如果你迷路了
exercise37.復(fù)習(xí)符號(hào)
exercise47.自動(dòng)化測(cè)試
exercise3.數(shù)字和數(shù)學(xué)計(jì)算
附錄 A-練習(xí) 1:安裝
exercise32.循環(huán)和列表
exercise31.做出決定
exercise42.對(duì)象、類(lèi)、以及從屬關(guān)系
exercise48.更復(fù)雜的用戶輸入
下一步
簡(jiǎn)介
附錄 A-練習(xí) 7:刪除路徑 (rmdir)
exercise49.寫(xiě)代碼語(yǔ)句
exercise18.命名, 變量, 代碼, 函數(shù)
exercise12.提示別人
exercise14.提示和傳遞
exercise40.模塊, 類(lèi)和對(duì)象
附錄 A-練習(xí) 12:查看文件 (less, MORE)
exercise9.打印, 打印, 打印
exercise13.參數(shù), 解包, 變量
exercise30. Else 和 If
exercise28. 布爾表達(dá)式
附錄 A-練習(xí) 4:創(chuàng)建一個(gè)路徑 (mkdir)
附錄 A-練習(xí) 15:退出命令行 (exit)
exercise25. 更多更多的練習(xí)
exercise6.字符串和文本
exercise2.注釋和井號(hào)“#”
exercise21. 函數(shù)的返回值
附錄 A-下一步
exercise1.第一個(gè)程序
exercise23. 閱讀代碼
附錄 A-練習(xí) 5:改變當(dāng)前路徑 (cd)
exercise17.更多文件操作
exercise24. 更多的練習(xí)
exercise19.函數(shù)和變量
exercise51.從瀏覽器獲取輸入
exercise22. 到目前為止你學(xué)到了什么?
exercise41.學(xué)會(huì)說(shuō)面向?qū)ο?/span>
exercise52.開(kāi)始你的 web 游戲
exercise20. 函數(shù)和文件
exercise15.讀文件
exercise45.你來(lái)制作一個(gè)游戲
exercise10.那是什么?
exercise8.打印, 打印
exercise35.分支和函數(shù)
exercise26. 恭喜你,可以進(jìn)行一次考試了
exercise33.while 循環(huán)
exercise29. IF 語(yǔ)句
exercise36.設(shè)計(jì)和調(diào)試
exercise0.安裝和準(zhǔn)備
exercise50.你的第一個(gè)網(wǎng)站
附錄 A-練習(xí) 2:路徑, 文件夾, 名錄 (pwd)
exercise38.列表操作
附錄 A-練習(xí) 6:列出當(dāng)前路徑 (ls)
exercise16.讀寫(xiě)文件
exercise4.變量和命名
exercise34.訪問(wèn)列表元素
exercise11.提問(wèn)
exercise43.基本的面向?qū)ο蟮姆治龊驮O(shè)計(jì)
附錄 A-簡(jiǎn)介
附錄 A-練習(xí) 8:目錄切換(pushd, popd)
來(lái)自老程序員的建議
exercise27. 記住邏輯
exercise5.更多的變量和打印
exercise7.更多的打?。ㄝ敵觯?/span>
附錄 A-練習(xí) 13:輸出文件 (cat)
exercise39.字典,可愛(ài)的字典

exercise50.你的第一個(gè)網(wǎng)站

最后的 3 個(gè)練習(xí)將會(huì)很難,你需要在他們身上多花一些時(shí)間。第一個(gè)練習(xí)里你將創(chuàng)建一個(gè)簡(jiǎn)單的 web 版本的游戲。在你開(kāi)始這節(jié)練習(xí)以前,你必須已經(jīng)成功地完成過(guò)了《習(xí)題 46》的內(nèi)容,正確安裝了 pip,而且學(xué)會(huì)了如何安裝軟件包以及如何創(chuàng)建項(xiàng)目骨架。如果你不記得這些內(nèi)容,就回到《習(xí)題 46》重新復(fù)習(xí)一遍。

安裝 lpthw.web

在創(chuàng)建你的第一個(gè)網(wǎng)頁(yè)應(yīng)用程序之前,你需要安裝一個(gè)“Web 框架”,它的名字叫 lpthw.web。所謂的“框架”通常是指“讓某件事情做起來(lái)更容易的軟件包”。在網(wǎng)頁(yè)應(yīng)用的世界里,人們創(chuàng)建了各種各樣的“網(wǎng)頁(yè)框架”,用來(lái)解決他們?cè)趧?chuàng)建網(wǎng)站時(shí)碰到的問(wèn)題,然后把這些解決方案用軟件包的方式發(fā)布出來(lái),這樣你就可以利用它們引導(dǎo)創(chuàng)建你自己的項(xiàng)目了。

可選的框架類(lèi)型有很多很多,不過(guò)在這里我們將使用 lpthw.web 框架。你可以先學(xué)會(huì)它,等到差不多的時(shí)候再去接觸其它的框架,不過(guò) lpthw.web 本身挺不錯(cuò)的,所以就算你一直使用也沒(méi)關(guān)系。

使用 pip 安裝 lpthw.web:

$ sudo pip install lpthw.web
[sudo] password for zedshaw:
Downloading/unpacking lpthw.web
  Running setup.py egg_info for package lpthw.web

Installing collected packages: lpthw.web
  Running setup.py install for lpthw.web

Successfully installed lpthw.web
Cleaning up...

以上是 Linux 和 Mac OSX 系統(tǒng)下的安裝命令,如果你使用的是 Windows,那你只要把 sudo 去掉就可以了。如果你無(wú)法正常安裝,請(qǐng)回到《習(xí)題 46》,確認(rèn)自己學(xué)會(huì)了里邊的內(nèi)容。

Warning: 其他 Python 程序員會(huì)警告你說(shuō) lpthw.web 只是另外一個(gè)叫做 web.py 的 Web 框架的代碼分支(fork),而 web.py 又包含了太多的“魔法(magic)”在里邊。如果他們這么說(shuō)的話,你告訴他們 Google App Engine 最早用的就是 web.py,但沒(méi)有一個(gè) Python 程序員抱怨過(guò)它里邊包含了太多的魔法,因?yàn)?Google 用它也沒(méi)啥問(wèn)題。如果 Google 覺(jué)得它可以,那它對(duì)你來(lái)說(shuō)也不會(huì)差。所以還是回去繼續(xù)學(xué)習(xí)吧,他們這些說(shuō)法與其說(shuō)是教導(dǎo)你,不如說(shuō)是拿他們自己的教條束縛你,你還是忽略這些說(shuō)法好了。

寫(xiě)一個(gè)簡(jiǎn)單的“Hello World”項(xiàng)目

現(xiàn)在我們使用 lpthw.web 做一個(gè)非常簡(jiǎn)單的“Hello World”項(xiàng)目出來(lái),首先你要?jiǎng)?chuàng)建一個(gè)項(xiàng)目目錄:

$ cd projects
$ mkdir gothonweb
$ cd gothonweb
$ mkdir bin gothonweb tests docs templates
$ touch gothonweb/__init__.py
$ touch tests/__init__.py

你最終的目的是把《習(xí)題 43》中的游戲做成一個(gè) web 應(yīng)用,所以你的項(xiàng)目名稱叫做 gothonweb,不過(guò)在此之前,你需要?jiǎng)?chuàng)建一個(gè)最基本的 lpthw.web 應(yīng)用,將下面的代碼放到 bin/app.py 中:

import web

urls = (
  '/', 'index'
)

app = web.application(urls, globals())

class index:
    def GET(self):
        greeting = "Hello World"
        return greeting

if __name__ == "__main__":
    app.run()

然后使用下面的方法來(lái)運(yùn)行這個(gè) web 程序:

$ python bin/app.py
http://0.0.0.0:8080/

如果你這樣做:

$ cd bin/   # WRONG! WRONG! WRONG!
$ python app.py  # WRONG! WRONG! WRONG!

那么你就錯(cuò)了。在所有 Python 項(xiàng)目中,都不會(huì)用 cd 到下一級(jí)目錄中去啟動(dòng)服務(wù),你就在最頂層的目錄啟動(dòng)服務(wù),這樣所有的系統(tǒng)可以訪問(wèn)所有的模塊和文件。 去重讀習(xí)題 46 并理解項(xiàng)目布局和如何使用它。

最后,使用你的網(wǎng)頁(yè)瀏覽器,打開(kāi) URL http://localhost:8080/,你應(yīng)該看到兩樣?xùn)|西,首先是瀏覽器里顯示了 Hello, world!,然后是你的命令行終端顯示了如下的輸出:

$ python bin/app.py
http://0.0.0.0:8080/
127.0.0.1:59542 - - [13/Jun/2011 11:44:43] "HTTP/1.1 GET /" - 200 OK
127.0.0.1:59542 - - [13/Jun/2011 11:44:43] "HTTP/1.1 GET /favicon.ico" - 404 Not Found

這些是 lpthw.web 打印出的 log 信息,從這些信息你可以看出服務(wù)器有在運(yùn)行,而且能了解到程序在瀏覽器背后做了些什么事情。這些信息還有助于你發(fā)現(xiàn)程序的問(wèn)題。例如在最后一行它告訴你瀏覽器試圖獲取/favicon.ico,但是這個(gè)文件并不存在,因此它返回的狀態(tài)碼是 404 Not Found。

到這里,我還沒(méi)有講到任何 web 相關(guān)的工作原理,因?yàn)槭紫饶阈枰瓿蓽?zhǔn)備工作,以便后面的學(xué)習(xí)能順利進(jìn)行,接下來(lái)的兩節(jié)習(xí)題中會(huì)有詳細(xì)的解釋。我會(huì)要求你用各種方法把你的 lpthw.web 應(yīng)用程序弄壞,然后再將其重新構(gòu)建起來(lái):這樣做的目的是讓你明白運(yùn)行 lpthw.web 程序需要準(zhǔn)備好哪些東西.

發(fā)生了什么?

在瀏覽器訪問(wèn)到你的網(wǎng)頁(yè)應(yīng)用程序時(shí),發(fā)生了下面一些事情:

1.瀏覽器通過(guò)網(wǎng)絡(luò)連接到你自己的電腦,它的名字叫做 localhost,這是一個(gè)標(biāo)準(zhǔn)稱謂,表示的誰(shuí)就是網(wǎng)絡(luò)中你自己的這臺(tái)計(jì)算機(jī),不管它實(shí)際名字是什么,你都可以使用 localhost 來(lái)訪問(wèn)。它使用到的網(wǎng)絡(luò)端口是 8080。 2.連接成功以后,瀏覽器對(duì) bin/app.py 這個(gè)應(yīng)用程序發(fā)出了 HTTP 請(qǐng)求(request),要求訪問(wèn) URL /,這通常是一個(gè)網(wǎng)站的第一個(gè) URL。 3.在 bin/app.py 里,我們有一個(gè)列表,里邊包含了 URL 和類(lèi)的匹配關(guān)系。我們這里只定義了一組匹配,那就是 '/', 'index' 的匹配。它的含義是:如果有人使用瀏覽器訪問(wèn) / 這一級(jí)目錄,lpthw.web 將找到并加載 class index,從而用它處理這個(gè)瀏覽器請(qǐng)求。 4.現(xiàn)在 lpthw.web 找到了 class index,然后針對(duì)這個(gè)類(lèi)的一個(gè)實(shí)例調(diào)用了 index.GET 這個(gè)方法函數(shù)。該函數(shù)運(yùn)行后返回了一個(gè)字符串,以供 lpthw.web 將其傳遞給瀏覽器。 5.最后 lpthw.web 完成了對(duì)于瀏覽器請(qǐng)求的處理,將響應(yīng)(response)回傳給瀏覽器,于是你就看到了現(xiàn)在的頁(yè)面。

確定你真的弄懂了這些,你需要畫(huà)一個(gè)流程圖,來(lái)理清信息是如何從瀏覽器傳遞到 lpthw.web,再到 index.GET,再回到你的瀏覽器的。

修正錯(cuò)誤

第一步,把第 11 行的 greeting 變量賦值刪掉,然后刷新瀏覽器。你應(yīng)該會(huì)看到一個(gè)錯(cuò)誤頁(yè)面,你可以通過(guò)這一頁(yè)豐富的錯(cuò)誤信息看出你的程序崩潰的原因是什么。當(dāng)然你已經(jīng)知道出錯(cuò)的原因是 greeting 的賦值丟失了,不過(guò) lpthw.web 還是會(huì)給你一個(gè)挺好的錯(cuò)誤頁(yè)面,讓你能找到出錯(cuò)的具體位置。試試在這個(gè)錯(cuò)誤頁(yè)面上做以下操作:

1.檢查每一段 Local vars 輸出(用鼠標(biāo)點(diǎn)擊它們),追蹤里邊提到的變量名稱,以及它們是在哪些代碼文件中用到的。 2.閱讀 Request Information 一節(jié),看看里邊哪些知識(shí)是你已經(jīng)熟悉了的。Request 是瀏覽器發(fā)給你的 gothonweb 應(yīng)用程序的信息。這些知識(shí)對(duì)于日常網(wǎng)頁(yè)瀏覽沒(méi)有什么用處,但現(xiàn)在你要學(xué)會(huì)這些東西,以便寫(xiě)出 web 應(yīng)用程序來(lái)。 3.試著把這個(gè)小程序的別的位置改錯(cuò),探索一下會(huì)發(fā)生什么事情。lpthw.web 的會(huì)把一些錯(cuò)誤信息和堆棧跟蹤(stack trace)信息顯示在命令行終端,所以別忘了檢查命令行終端的信息輸出。

創(chuàng)建基本的模板文件

你已經(jīng)試過(guò)用各種方法把這個(gè) lpthw.web 程序改錯(cuò),不過(guò)你有沒(méi)有注意到“Hello World”不是一個(gè)好 HTML 網(wǎng)頁(yè)呢?這是一個(gè) web 應(yīng)用,所以需要一個(gè)合適的 HTML 響應(yīng)頁(yè)面才對(duì)。為了達(dá)到這個(gè)目的,下一步你要做的是將“Hello World”以較大的綠色字體顯示出來(lái)。

第一步是創(chuàng)建一個(gè) templates/index.html 文件,內(nèi)容如下:

$def with (greeting)

<html>
    <head>
        <title>Gothons Of Planet Percal #25</title>
    </head>
<body>

$if greeting:
    I just wanted to say <em style="color: green; font-size: 2em;">$greeting</em>.
$else:
    <em>Hello</em>, world!

</body>
</html>

如果你學(xué)過(guò) HTML 的話,這些內(nèi)容你看上去應(yīng)該很熟悉。如果你沒(méi)學(xué)過(guò) HTML,那你應(yīng)該去研究一下,試著用 HTML 寫(xiě)幾個(gè)網(wǎng)頁(yè),從而知道它的工作原理。不過(guò)我們這里的 HTML 文件其實(shí)是一個(gè)“模板(template)”,如果你向模板提供一些參數(shù),lpthw.web 就會(huì)在模板中找到對(duì)應(yīng)的位置,將參數(shù)的內(nèi)容填充到模板中。例如每一個(gè)出現(xiàn) $greeting 的位置,$greeting 的內(nèi)容都會(huì)被替換成對(duì)應(yīng)這個(gè)變量名的參數(shù)。

為了讓你的 bin/app.py 處理模板,你需要寫(xiě)一寫(xiě)代碼,告訴 lpthw.web 到哪里去找到模板進(jìn)行加載,以及如何渲染(render)這個(gè)模板,按下面的方式修改你的 app.py:

import web

urls = (
  '/', 'Index'
)

app = web.application(urls, globals())

render = web.template.render('templates/')

class Index(object):
    def GET(self):
        greeting = "Hello World"
        return render.index(greeting = greeting)

if __name__ == "__main__":
    app.run()

特別注意一下 render 這個(gè)新變量名,注意我修改了 index.GET 的最后一行,讓它返回了 render.index(),并且將 greeting 變量作為參數(shù)傳遞給了這個(gè)函數(shù)。

改好上面的代碼后,刷新一下瀏覽器中的網(wǎng)頁(yè),你應(yīng)該會(huì)看到一條和之前不同的綠色信息輸出。你還可以在瀏覽器中通過(guò)“查看源文件(View Source)”看到模板被渲染成了標(biāo)準(zhǔn)有效的 HTML 源代碼。

這么講也許有些太快了,我來(lái)詳細(xì)解釋一下模板的工作原理吧:

1.在 bin/app.py 里面你添加了一個(gè)叫做 render 的新變量,它本身是一個(gè) web.template.render 對(duì)象。 2.你將 templates/ 作為參數(shù)傳遞給了這個(gè)對(duì)象,這樣就讓 render 知道了從哪里去加載模板文件。 3.在你后面的代碼中,當(dāng)瀏覽器一如既往地觸發(fā)了 index.GET 以后,它沒(méi)有再返回簡(jiǎn)單的 greeting 字符串,取而代之的是你調(diào)用了 render.index,而且將問(wèn)候語(yǔ)句作為一個(gè)變量傳遞給它。 4.這個(gè) render_template 函數(shù)可以說(shuō)是一個(gè)“魔法函數(shù)”,它看到了你需要的是 index.html,于是就跑到 templates/目錄下,找到名字為 index.html 的文件,然后就把它渲染(render)一遍(叫“轉(zhuǎn)換一遍”也可以)。 5.在 templates/index.html 文件中,你可以看到初始定義一行中說(shuō)這個(gè)模板需要使用一個(gè)叫 greeting 的參數(shù),這和函數(shù)定義中的格式差不多。另外和 Python 語(yǔ)法一樣,模板文件是縮進(jìn)敏感的,所以要確認(rèn)自己弄對(duì)了縮進(jìn)。 6.最后,你讓 templates/index.html 去檢查 greeting 這個(gè)變量,如果這個(gè)變量存在的話,就打印出變量的內(nèi)容,如果不存在的話,就會(huì)打印出一個(gè)默認(rèn)的問(wèn)候信息。

要深入理解這個(gè)過(guò)程,你可以修改 greeting 變量以及 HTML 模板的內(nèi)容,看看會(huì)有什么效果。然后創(chuàng)建一個(gè)叫做 templates/foo.html 的模板,并且使用一個(gè)新的 render.foo()去渲染它。從這個(gè)過(guò)程你也可以看出, render 調(diào)用的函數(shù)名稱只要跟 templates/下的 .html 文件名匹配到,這個(gè) HTML 模板就可以被渲染到了。

附加題

1.閱讀 http://webpy.org/ 里邊的文檔,它其實(shí)和 lpthw.web 是同一個(gè)項(xiàng)目。 2.實(shí)驗(yàn)一下你在上述網(wǎng)站看到的所有的東西,包括里邊的代碼示例。 3.閱讀以下 HTML5 和 CSS3 相關(guān)的東西,自己練習(xí)著寫(xiě)幾個(gè) .html 和 .css 文件。 4.如果你有一個(gè)懂 Django 朋友可以幫你的話,你可以試著使用 Django 完成一下習(xí)題 50、51、52,看看結(jié)果會(huì)是什么樣子的。

常見(jiàn)問(wèn)題

Q: 我好想無(wú)法連接到 http://localhost:8080/

那么試試訪問(wèn) http://127.0.0.1:8080/

Q: lpthw.web 和 web.py 有什么區(qū)別?

沒(méi)有區(qū)別。我只是在特定版本“鎖定”web.py,以使它對(duì)所有學(xué)生都是一樣的,然后再命名為 lpthw.web,上一個(gè)版本的 web.py 可能就不同于這一版本。

Q: 我的代碼找不到 index.html(或者其他文件)

你可能是先執(zhí)行了 cd bin/,不要執(zhí)行這一句,所有的命令都應(yīng)該在 bin/的上一級(jí)目錄執(zhí)行,所以如果你不能執(zhí)行 python bin/app.py,說(shuō)明你在錯(cuò)誤的目錄上。

Q: 當(dāng)我們調(diào)用模板的時(shí)候,為什么要執(zhí)行 greeting=greeting 賦值操作

你并沒(méi)有給 greeting 賦值,你只是給模板設(shè)定一個(gè)命名參數(shù)。這是聲明的一種,但它只影響調(diào)用模板的功能。

Q: 我的電腦上不能使用 8080 端口

你可能有一個(gè)殺毒程序占用了這個(gè)端口,試試別的端口。

Q: 安裝 lpthw.web 時(shí),我遇到報(bào)錯(cuò)信息 ImportError "No module named web"

你可能安裝了多個(gè)版本的 Python 并且正在使用一個(gè)錯(cuò)誤的版本,或者你是因?yàn)槭褂昧艘粋€(gè)舊版本的 pip,導(dǎo)致安裝沒(méi)有成功,試著先卸載 lpthw.web,在重裝一次,如果還沒(méi)有解決問(wèn)題,再次確認(rèn)下你是否使用了正確的 Python 版本。