<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    習題 49: 創建句子?

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

                    >>> from ex48 import lexicon
                    >>> print lexicon.scan("go north")
                    [('verb', 'go'), ('direction', 'north')]
                    >>> print lexicon.scan("kill the princess")
                    [('verb', 'kill'), ('stop', 'the'), ('noun', 'princess')]
                    >>> print lexicon.scan("eat the bear")
                    [('verb', 'eat'), ('stop', 'the'), ('noun', 'bear')]
                    >>> print lexicon.scan("open the door and smack the bear in the nose")
                    [('error', 'open'), ('stop', 'the'), ('noun', 'door'), ('error', 'and'),
                    ('error', 'smack'), ('stop', 'the'), ('noun', 'bear'), ('stop', 'in'),
                    ('stop', 'the'), ('error', 'nose')]
                    >>>
                    

                    現在讓我們把它轉化成游戲可以使用的東西,也就是一個 Sentence 類。

                    如果你還記得學校學過的東西的話,一個句子是由這樣的結構組成的:

                    主語(Subject) + 謂語(動詞 Verb) + 賓語(Object)

                    很顯然實際的句子可能會比這復雜,而你可能已經在英語的語法課上面被折騰得夠嗆了。我們的目的,是將上面的元組列表轉換為一個 Sentence 對象,而這個對象又包含主謂賓各個成員。

                    匹配(Match)和窺視(Peek)?

                    為了達到這個效果,你需要四樣工具:

                    1. 循環訪問元組列表的方法,這挺簡單的。
                    2. 匹配我們的主謂賓設置中不同種類元組的方法。
                    3. 一個“窺視”潛在元組的方法,以便做決定時用到。
                    4. 跳過(skip)我們不在乎的內容的方法,例如形容詞、冠詞等沒有用處的詞匯。

                    我們使用 peek 函數來查看元組列表中的下一個成員,做匹配以后再對它做下一步動作。讓我們先看看這個 peek 函數:

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

                    很簡單。再看看 match 函數:

                    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
                    

                    還是很簡單,最后我們看看 skip 函數:

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

                    以你現在的水平,你應該可以看出它們的功能來。確認自己真的弄懂了它們。

                    句子的語法?

                    有了工具,我們現在可以從元組列表來構建句子(Sentence)對象了。我們的處理流程如下:

                    1. 使用 peek 識別下一個單詞。
                    2. 如果這個單詞和我們的語法匹配,我們就調用一個函數來處理這部分語法。假設函數的名字叫 parse_subject 好了。
                    3. 如果語法不匹配,我們就 raise 一個錯誤,接下來你會學到這方面的內容。
                    4. 全部分析完以后,我們應該能得到一個 Sentence 對象,然后可以將其應用在我們的游戲中。

                    演示這個過程最簡單的方法是把代碼展示給你讓你閱讀,不過這節習題有個不一樣的要求,前面是我給你測試代碼,你照著寫出程序來,而這次是我給你的程序,而你要為它寫出測試代碼來。

                    以下就是我寫的用來解析簡單句子的代碼,它使用了 ex48.lexicon 這個模組。

                    class ParserError(Exception):
                        pass
                    
                    
                    class Sentence(object):
                    
                        def __init__(self, subject, verb, object):
                            # remember we take ('noun','princess') tuples and convert them
                            self.subject = subject[1]
                            self.verb = verb[1]
                            self.object = object[1]
                    
                    
                    def peek(word_list):
                        if word_list:
                            word = word_list[0]
                            return word[0]
                        else:
                            return None
                    
                    
                    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
                    
                    
                    def skip(word_list, word_type):
                        while peek(word_list) == word_type:
                            match(word_list, word_type)
                    
                    
                    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.")
                    
                    
                    def parse_object(word_list):
                        skip(word_list, 'stop')
                        next = peek(word_list)
                    
                        if next == 'noun':
                            return match(word_list, 'noun')
                        if next == 'direction':
                            return match(word_list, 'direction')
                        else:
                            raise ParserError("Expected a noun or direction next.")
                    
                    
                    def parse_subject(word_list, subj):
                        verb = parse_verb(word_list)
                        obj = parse_object(word_list)
                    
                        return Sentence(subj, verb, obj)
                    
                    
                    def parse_sentence(word_list):
                        skip(word_list, 'stop')
                    
                        start = peek(word_list)
                    
                        if start == 'noun':
                            subj = match(word_list, 'noun')
                            return parse_subject(word_list, subj)
                        elif start == 'verb':
                            # assume the subject is the player then
                            return parse_subject(word_list, ('noun', 'player'))
                        else:
                            raise ParserError("Must start with subject, object, or verb not: %s" % start)
                    

                    關于異常(Exception)?

                    你已經簡單學過關于異常的一些東西,但還沒學過怎樣拋出(raise)它們。這節的代碼演示了如何 raise 前面定義的 ParserError。注意 ParserError 是一個定義為 Exception 類型的 class。另外要注意我們是怎樣使用 raise 這個關鍵字來拋出異常的。

                    你的測試代碼應該也要測試到這些異常,這個我也會演示給你如何實現。

                    你應該測試的東西?

                    為《習題 49》寫一個完整的測試方案,確認代碼中所有的東西都能正常工作,其中異常的測試——輸入一個錯誤的句子它會拋出一個異常來。

                    使用 assert_raises 這個函數來檢查異常,在 nose 的文檔里查看相關的內容,學著使用它寫針對“執行失敗”的測試,這也是測試很重要的一個方面。從 nose 文檔中學會使用 assert_raises,以及一些別的函數。

                    寫完測試以后,你應該就明白了這段程序的工作原理,而且也學會了如何為別人的程序寫測試代碼。 相信我,這是一個非常有用的技能。

                    加分習題?

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

                    Project Versions

                    Table Of Contents

                    Previous topic

                    習題 48: 更復雜的用戶輸入

                    Next topic

                    習題 50: 你的第一個網站

                    This Page

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频