在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ exercise49.寫代碼語(yǔ)句
附錄 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ì)象、類、以及從屬關(guān)系
exercise48.更復(fù)雜的用戶輸入
下一步
簡(jiǎn)介
附錄 A-練習(xí) 7:刪除路徑 (rmdir)
exercise49.寫代碼語(yǔ)句
exercise18.命名, 變量, 代碼, 函數(shù)
exercise12.提示別人
exercise14.提示和傳遞
exercise40.模塊, 類和對(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.開始你的 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.讀寫文件
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.字典,可愛的字典

exercise49.寫代碼語(yǔ)句

從這個(gè)小游戲的詞匯掃描器中,我們應(yīng)該可以得到類似下面的列表:

python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from ex48 import lexicon
>>> lexicon.scan("go north")
[('verb', 'go'), ('direction', 'north')]
>>> lexicon.scan("kill the princess")
[('verb', 'kill'), ('stop', 'the'), ('noun', 'princess')]
>>> lexicon.scan("eat the bear")
[('verb', 'eat'), ('stop', 'the'), ('noun', 'bear')]
>>> lexicon.scan("open the door and smack the bear in the nose")
[('error', 'open'), ('stop', 'the'), ('error', 'door'), ('error', 'and'), ('error', 'smack'), ('stop', 'the'), ('noun', 'bear'), ('stop', 'in'), ('stop', 'the'), ('error', 'nose')]

現(xiàn)在讓我們把它轉(zhuǎn)化成游戲可以使用的東西,也就是一個(gè) Sentence 類。

如果你還記得學(xué)校學(xué)過(guò)的東西的話,一個(gè)句子是由這樣的結(jié)構(gòu)組成的: 主語(yǔ)(Subject) + 謂語(yǔ)(動(dòng)詞 Verb) + 賓語(yǔ)(Object)

很顯然實(shí)際的句子可能會(huì)比這復(fù)雜,而你可能已經(jīng)在英語(yǔ)的語(yǔ)法課上面被折騰得夠嗆了。我們的目的,是將上面的元組列表轉(zhuǎn)換為一個(gè) Sentence 對(duì)象,而這個(gè)對(duì)象又包含主謂賓各個(gè)成員。

匹配(Match)和窺視(Peek)

為了達(dá)到這個(gè)效果,你需要四(五)樣工具:

1.循環(huán)訪問(wèn)元組列表的方法,這挺簡(jiǎn)單的。 2.匹配我們的主謂賓設(shè)置中不同種類元組的方法。 3.一個(gè)“窺視”潛在元組的方法,以便做決定時(shí)用到。 4.跳過(guò)(skip)我們不在乎的內(nèi)容的方法,例如形容詞、冠詞等沒有用處的詞匯。 5.一個(gè)用來(lái)存放最終結(jié)果的 Sentence 對(duì)象

我們要把這些函數(shù)放在一個(gè)叫做 ex48.parser 的類中,再把這個(gè)類放在 ex48/parser.py 中,以便于我們能夠測(cè)試它們。我們使用 peek 函數(shù)來(lái)查看元組列表中的下一個(gè)成員,做匹配以后再對(duì)它做下一步動(dòng)作。

句子的語(yǔ)法

在你寫代碼之前,你要弄明白一個(gè)基礎(chǔ)的英語(yǔ)句子的語(yǔ)法是如何工作的。在我們的練習(xí)中,我們準(zhǔn)備創(chuàng)建一個(gè)叫做 Sentence 的類,它有如下 3 個(gè)屬性:

Sentence.subject(句子的主語(yǔ)) 這是任意一個(gè)句子的主語(yǔ),大部分時(shí)候可以默認(rèn)為“玩家 player”,比如一個(gè)句子“run north 向北跑”, 也就是說(shuō) "player run north 玩家向北跑"。主語(yǔ)應(yīng)該是一個(gè)名詞。

Sentence.verb(句子的謂語(yǔ)) 這就是句子的的作用。 在 "run north" 中,謂語(yǔ)應(yīng)該是 "run". 謂語(yǔ)應(yīng)該是一個(gè)動(dòng)詞。

Sentence.object(句子的賓語(yǔ)) 這又是一個(gè)名詞,指的是動(dòng)詞做了什么。在我們游戲中, 我們分辨出的方向就是賓語(yǔ)。在 "run north" 中,單詞"north"就是賓語(yǔ)。在 "hit bear" 中,單詞"bear" 就是賓語(yǔ)。

我們的程序解析器使用我們給出的函數(shù)并返回解析后的句子,轉(zhuǎn)換成一個(gè) list 或 Sentence 對(duì)象,用來(lái)接收匹配用戶輸入

關(guān)于異常(Exception)

已經(jīng)簡(jiǎn)單學(xué)過(guò)關(guān)于異常的一些東西,但還沒學(xué)過(guò)怎樣拋出(raise)它們。這節(jié)的代碼演示了如何 raise 前面定義的 ParserError。注意 ParserError 是一個(gè)定義為 Exception 類型的 class。另外要注意我們是怎樣使用 raise 這個(gè)關(guān)鍵字來(lái)拋出異常的。

你的測(cè)試代碼應(yīng)該也要測(cè)試到這些異常,這個(gè)我也會(huì)演示給你如何實(shí)現(xiàn)。

程序代碼

如果你希望更大的挑戰(zhàn),停在這里,然后只聽我的描述來(lái)完成代碼。當(dāng)你遇到難題的時(shí)候,可以再回來(lái)看看是我如何做的。不過(guò),嘗試自己實(shí)現(xiàn)代碼功能對(duì)你來(lái)說(shuō)真的是個(gè)很好的鍛煉。我要開始串講我的代碼了,你可以開始在自己的 ex48/parser.py 中輸入代碼。我們從異常處理開始我們的代碼編寫:

class ParserError(Exception):
    pass

這就是你創(chuàng)建一個(gè)可以拋出的異常類 ParserError,接下來(lái),我們需要一個(gè)句子類 Sentence:

class Sentence(object):

    def __init__(self, subject, verb, obj):
        # remember we take ('noun','princess') tuples and convert them
        self.subject = subject[1]
        self.verb = verb[1]
        self.object = obj[1]

到目前為止,我們沒有寫什么特別的代碼,只是創(chuàng)建了兩個(gè)簡(jiǎn)單的類。

在我們的問(wèn)題描述中,我們需要一個(gè)函數(shù)用來(lái)看到列表中的單詞并返回單詞的類型:

def peek(word_list):
    if word_list:
        word = word_list[0]
        return word[0]
    else:
        return None

我們需要這個(gè)函數(shù)是因?yàn)椋覀円谙乱粋€(gè)單詞來(lái)選擇確認(rèn)我們要處理的句子是什么,然后我們可以調(diào)用另一個(gè)函數(shù)來(lái)處理這個(gè)單詞,并將程序繼續(xù)下去。

我們使用 match 函數(shù)來(lái)處理單詞,用它來(lái)確認(rèn)預(yù)期中的單詞是否是正確的類型,將它移出列表,并返回該詞:

def match(word_list, expecting):
    if word_list:
        word = word_list.pop(0)

        if word[0] == expecting:
            return word
        else:
            return None
    else:
        return None

相當(dāng)簡(jiǎn)單是不是,不過(guò)還是要確認(rèn)你理解了這些代碼以及為什么我是這么寫的。我需要依據(jù)我看到的列表中的下一個(gè)單詞來(lái)決定我現(xiàn)在處理的句子的類型,然后再用這個(gè)單詞創(chuàng)建我的 Sentence.

最后,我們需要一個(gè)方法來(lái)跳過(guò)句子中我們不關(guān)心的單詞。這些單詞會(huì)被打上“停用詞”(stop 類型的詞)的標(biāo)簽,比如"the","and"以及"a"等:

def skip(word_list, word_type):
    while peek(word_list) == word_type:
        match(word_list, word_type)

記住 skip 不只跳過(guò)一個(gè)單詞而是跳過(guò)所有該類型的詞,也就是說(shuō),如果有人輸入了“scream at the bear”,經(jīng)過(guò)處理最后會(huì)得到"scream" 和 "bear".

以上是我們分析函數(shù)的基本結(jié)構(gòu),我可以用它們來(lái)處理我們需要的任何文本,盡管我們的程序非常簡(jiǎn)單,剩下的函數(shù)也都是非常短的。

首先,我們來(lái)完成解析動(dòng)詞的部分:

def parse_verb(word_list):
    skip(word_list, 'stop')

    if peek(word_list) == 'verb':
        return match(word_list, 'verb')
    else:
        raise ParserError("Expected a verb next.")

我們跳過(guò)所有"stop"類型的詞,然后提前獲得下一個(gè)單詞,并確認(rèn)它是"verb"類型,如果不是,則拋出一個(gè)異常 ParserError 說(shuō)明為什么不是。如果是"verb"類型,則使用"match"處理,將它移出列表。一個(gè)處理"sentence"類的類似函數(shù):

def parse_object(word_list):
    skip(word_list, 'stop')
    next_word = peek(word_list)

    if next_word == 'noun':
        return match(word_list, 'noun')
    elif next_word == 'direction':
        return match(word_list, 'direction')
    else:
        raise ParserError("Expected a noun or direction next.")

重復(fù)操作,跳過(guò)"stop"類型的詞,提前判斷下一個(gè)詞,決定下一個(gè)"sentence".在函數(shù) parse_object 中,我們需要同時(shí)處理“名詞”和類似賓語(yǔ)的“方向”,解析主語(yǔ)的方法也是一樣的,但是當(dāng)我們處理隱藏的名詞"player"的時(shí)候,我們需要用到"peek":

def parse_subject(word_list):
    skip(word_list, 'stop')
    next_word = peek(word_list)

    if next_word == 'noun':
        return match(word_list, 'noun')
    elif next_word == 'verb':
        return ('noun', 'player')
    else:
        raise ParserError("Expected a verb next.")

所有的方式都準(zhǔn)備好之后,我們最后一個(gè)函數(shù) parse_sentence 也是非常簡(jiǎn)單的:

def parse_sentence(word_list):
    subj = parse_subject(word_list)
    verb = parse_verb(word_list)
    obj = parse_object(word_list)

    return Sentence(subj, verb, obj)

試玩這個(gè)游戲

為了弄明白程序是如何運(yùn)行,你可以像這樣試玩:

Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from ex48.parser import *
>>> x = parse_sentence([('verb', 'run'), ('direction', 'north')])
>>> x.subject
'player'
>>> x.verb
'run'
>>> x.object
'north'
>>> x = parse_sentence([('noun', 'bear'), ('verb', 'eat'), ('stop', 'the'), ('noun', 'honey')])
>>> x.subject
'bear'
>>> x.verb
'eat'
>>> x.object
'honey'

你應(yīng)該測(cè)試的東西

為《習(xí)題 49》寫一個(gè)完整的測(cè)試方案,確認(rèn)代碼中所有的東西都能正常工作,把測(cè)試代碼放到文件 tests/parser_tests.py 中,測(cè)試代碼中也要包含對(duì)異常的測(cè)試——輸入一個(gè)錯(cuò)誤的句子它會(huì)拋出一個(gè)異常來(lái)。

使用 assert_raises 這個(gè)函數(shù)來(lái)檢查異常,在 nose 的文檔里查看相關(guān)的內(nèi)容,學(xué)著使用它寫針對(duì)“執(zhí)行失敗”的測(cè)試,這也是測(cè)試很重要的一個(gè)方面。從 nose 文檔中學(xué)會(huì) assert_raises 以及一些別的函數(shù)的使用方法。

寫完測(cè)試以后,你應(yīng)該就明白了這段程序的工作原理,而且也學(xué)會(huì)了如何為別人的程序?qū)憸y(cè)試代碼。 相信我,這是一個(gè)非常有用的技能。

附加題

1.修改 parse_函數(shù)(方法),將它們放到一個(gè)類里邊,而不僅僅是獨(dú)立的方法函數(shù)。這兩種程序設(shè)計(jì)你喜歡哪一種呢? 2.提高 parser 的容錯(cuò)能力,這樣即使用戶輸入了你預(yù)定義語(yǔ)匯之外的詞語(yǔ),你的程序也能正常運(yùn)行下去。 3.改進(jìn)語(yǔ)法,讓它可以處理更多的東西,例如數(shù)字。 4.想想在游戲里你的 Sentence 類可以對(duì)用戶輸入做哪些有趣的事情。

常見問(wèn)題

Q: 我好像不能讓 assert_raises 正常運(yùn)行

確認(rèn)你寫的是 assert_raises(exception, callable, parameters)而不是 assert_raises(exception, callable(parameters))。注意一下第二種寫法中,調(diào)用了函數(shù) callable 并將返回值傳遞給 assert_raises,這種寫法是錯(cuò)誤的,你應(yīng)該把要調(diào)用的函數(shù)也作為參數(shù)傳遞給 assert_raises。