跳到內容

選擇你自己的 Python 冒險 / 徘徊的格魯

來自華夏公益教科書,開放的書籍,為一個開放的世界

函式案例研究:徘徊的格魯

假設你想要在你神秘的房子裡放一個徘徊的格魯,它會隨機出現在一個房間(或多個房間)裡。

一種方法是建立一個函式,它決定格魯是否在房間裡。

測試框架

在我們的完整程式碼中,我們將看到類似的程式碼

eaten=grue()
if eaten:
    print "Sadly, you were torn limb-from-limb by the Grue and suffered a slow, painful death."
else:
    print "Congratulations, you have not been eaten by the Grue! May you have a long happy life."

這裡我們介紹了一種新的 Python 資料型別:布林值。Python 布林值可以取兩個值 TrueFalse。這些程式碼片段是等效的

   if x > 3:
       print "yep!"
   
   if x > 3 is True:
       print "yep!"
   
   if bool(x>3) is True:
       print "yep!"

“if” 語法隱含 如果謂詞為 True。在 Python 中,大多數東西都評估為 True除了:None、False、0(0.0 等)、空字串、零長度列表、字典,以及其他一些奇特的東西 [1].


變體 1:不太隨機

def grue_always():
    ''' this grue always appears.  returns true'''
    return True

我們不太隨機的格魯總是出現。

練習:建立相反情況——一個永遠不出現的格魯。函式的簽名應該是 grue_never() -> False


變體 2:50/50 格魯

import random 
## random is a Python module, as mentioned above. 
## We need to import it to access the random() function.
## now to begin the function definition
## Everything inside the function definition is indented! Remember, white space matters!
def random_grue(): 
    ''' boolean.  a grue that appears 50% of the time '''
    ## we want something that will return True 50% of the time.
    ## one method:  get a random float between (0,1), and return True if it's over .5
    ## now we need a random number. random() will give us one between 0 and 1
    n=random.random() ## the random before the dot tells Python what module to look in for the function, which is the one we imported above
    if n > 0.5:
        grue=1 ## 1 == True
    else:
        grue=0 ## 0 == False

    return grue ## returning allows us to capture the value


那麼 random_grue() 函式做了什麼?讓我們試試它。在 Python 直譯器中

    >>> import random
    >>> def random_grue():
            n=random.random()
            if n>0/5:
                    grue = 1
            else:
                    grue = 0
            return grue
  
    >>> random_grue()
    1

第一個命令是匯入 random 模組,第二個是定義函式,第三個是實際呼叫函式。1 是函式的返回值。你可能會得到 1 或 0,具體取決於 random() 生成的數字。(提示:嘗試執行多次)

> 關於偽隨機數的離題,以及每次都獲得相同數字的技巧!


變體 2:情緒化的格魯

import random 
def grue_moody(cutoff=.5): 
    ''' boolean.  a grue that appears (100*cutoff)% of the time '''
    n=random.random() 
    above_cutoff = n < cutoff
    return above_cutoff

def grue_moody2(cutoff=.5): 
    ''' boolean.  a grue that appears (100*cutoff)% of the time '''
    return random.random() < cutoff

注意我們透過直接返回布林值(尤其是在 'grue_moody2' 中)簡化了函式,而不是做任何條件邏輯來獲得 1 或 0。此外,我們還為引數 cutoff 指定了一個預設值

練習

  1. 預測這些函式呼叫的行為。然後試試它們。
    • grue_moody()
    • grue_moody(-1)
    • grue_moody(1)
    • grue_moody("a")
    • grue_moody([1,2,3])
  2. 修復程式碼,以便如果 n 超出區間 (0,1),則列印一條憤怒訊息並返回 None
  3. 嘗試 help(grue_moody)。你看到了什麼?
  4. randomrandom.randomrandom.random() 的型別是什麼?


變體 3:位置,位置,位置格魯

在我們最終的變體中,我們想要一個格魯

  • 根據頁面的不同,出現百分比不同
  • 在主房間“門廳”中應該沒有出現的可能性
  • 在沒有其他描述的房間裡,應該有一個預設的 5% 的出現機率
import random 
grue_fractions = { 'foyer':0, 'thedark': 1.0, 'nocake': .2 }

def location_grue(room=None, base=.05, cutoffs=dict()): 
    ''' (boolean), does a grue appear in the room?
    room : str room name
    base : 'cutoff', float between (0,1), for base (room not found)
    cutoffs: dict of room_name: cutoff (float between 0,1)
    '''
    cutoff = cutoffs[room]
    return random.random() < cutoff


練習

  1. 如寫,location_grue 有一些 bug,並且不符合規範。識別並修復它們。
    1. 嘗試:location_grue('foyer', cutoffs=grue_fractions)
    2. 如果 'room' 不在 'cutoffs' 中會發生什麼?
    3. 研究字典的 'get' 方法... help({}.get)。使用此方法來修復程式碼。

參考文獻

[編輯 | 編輯原始碼]
華夏公益教科書