python 函數封閉調用

python 函數封閉調用

明確項目目標:

互聯網公司有兩種角色,產品經理、程序員。產品經理提開發需求給程序員,然後程序員開發出滿足需求功能的程序。

今天我們來做個模擬,我們扮演“程序員”接到“產品經理”需求,並完成開發的過程。

需求文檔是這樣子的:

python 函數封閉調用

“敏捷開發”是互聯網的常態。剛剛當“程序員”的第一天,你就接到了這麼急的需求,那該怎麼辦呢?我們來分析一下。

分析過程,拆解項目

既然是個計算器程序,那就是要輸入信息後能計算出結果。為了搞清楚計算過程,我們需要根據案例倒推出計算公式。

我們先梳理一下需求文檔中的關鍵信息:

python 函數封閉調用

python 函數封閉調用

python 函數封閉調用

把程序版本大致規劃成三個階段:

python 函數封閉調用

逐步執行,代碼實現

要做一個“能用就好”的最基本的程序,我們可以直接編寫一個帶參數函數完成計算功能。程序寫出來大概長這個結構:

完善代碼的過程中,我們會用到第一個項目末尾提到的知識點:

格式化字符串

# 無需修改代碼,直接運行即可

# 工時計算

def estimated_time(size,number):

time = size * 80 / number

print('項目大小為%.1f個標準項目,使用%d個人力完成,則需要工時數量為:%.1f個' %(size,number,time))

# 人力計算

def estimated_numbeer(size,time):

number = size * 80 / time

print('項目大小為%.1f個標準項目,如果需要在%.1f個工時完成,則需要人力數量為:%d人' %(size,time,number))

# 調用工時計算函數

estimated_time(1.5,2)

# 調用人力計算函數

estimated_numbeer(0.8,25)

python 函數封閉調用

注:%f的意思是格式化字符串為浮點型,%.1f的意思是格式化字符串為浮點型,並保留1位小數。

第一步定位問題我們已經完成了:代碼的計算過程應該對對人數向上取整。也就是計算結果是1.5人的時候,取整數2,計算結果3.8人的時候,取整數4,計算結果10.1人的時候,取整數11……

第二步,我們可以直接尋找新知識,在搜索引擎中搜索“python 取整”,就能找到向上取整的函數。

python 函數封閉調用

其中import math是因為使用ceil()函數需要導入math模塊,就像第7關小遊戲項目中,使用randint()函數(隨機整數)需要導入random模塊。我們會在第15關詳細講解關於“模塊”的來龍去脈,現在你只需要讀懂代碼含義即可。

這個問題的解決還有另一種方式,在第二步的時候,你也可以運用已有知識解決。

有一個計算符不太常用,不知道你是否還記得:可以用%做取餘數運算,比如print(5%4)的結果是1(5除以4餘數為1)。

如果你想起了這個知識,那麼在第三步,我們可以找到一個切入點:如果人數不是整數(餘數不為零),就把人數用int()函數轉化為正數,然後再加1。

python 函數封閉調用

現在的問題又推進了一步:該如何設置條件,讓條件1代表人力計算,條件2代表工時計算?

這個問題有多種解法,關鍵點是利用參數設置條件。我先跟你演示一種:(請留意代碼註釋)

python 函數封閉調用

這裡的代碼用到了第9關默認參數的相關知識。在調用函數的時候,我們可以給指定的參數賦值,那剩餘的參數就會是默認值(也就是在定義函數的那行定義了他們的默認值)。比如estimated(size=1.5,time=20.0),給size和time賦值,那剩下的number就默認為None。

import math

# 為函數設置了三個參數,並都帶有默認參數

def estimated(size=1,number=None,time=None):

# 人力計算:如果參數中填了時間,沒填人數,就計算人力

if (number == None) and (time != None):

number = math.ceil(size * 80 / time)

print('項目大小為%.1f個標準項目,如果需要在%.1f個工時完成,則需要人力數量為:%d人' %(size,time,number))

# 工時計算:如果參數中填了人數,沒填時間,就計算工時

elif (number != None) and (time == None):

time = size * 80 / number

print('項目大小為%.1f個標準項目,使用%d個人力完成,則需要工時數量為:%.1f個' %(size,number,time))

# 調用函數的時候,傳遞兩個參數,會自動計算出第三個參數

estimated(size=1.5,number=2)

estimated(size=0.5,time=20.0)

剛才提到“合併成一個函數”這個問題不止一種解法。比如說,我們還可以這樣設置三個參數來實現相同的效果:

python 函數封閉調用

將以下代碼修改成剛才提到的第二種解決方案:

python 函數封閉調用

現在我們又拿到了新的需求:製作出“可以交互運行”的程序。

想讓程序可以交互,顯然要用input和print語句,這些都是我們曾經學過的。

為了方便,先把一些你可能需要複製的素材給你:

python 函數封閉調用

只要程序運行效果符合樣例演示效果即可。

python 函數封閉調用

到這裡,程序基本已經完成了。不過,為了展示用函數封裝代碼的精髓,我想再問大家一個問題:

可以創建一個主函數,用來調用幾個子函數。一起來溫習一下上個關卡的代碼:

python 函數封閉調用

python 函數封閉調用

用圖片來表示的話,是這樣的:

python 函數封閉調用

如圖所示,我們可以把每個獨立的功能封裝到每個單獨的函數中,然後用一個主函數打包這些單獨的函數,最後再調用主函數。

改造好了吧?看下參考代碼:

python 函數封閉調用

python 函數封閉調用

python 函數封閉調用

在這裡,myinput()函數負責跟用戶採集信息estimated()函數負責完成計算而main()函數把其他兩個函數打包放在一起並傳遞了參數。所以只要調用main()函數就能讓整個程序跑起來。你可以再次運行體驗一下。

import math

# 採集信息的函數

def myinput():

choice = input('請選擇計算類型:(1-人力計算,2-工時計算)')

if choice == '1':

size = float(input('請輸入項目大小:(1代表標準大小,請輸入小數)'))

number = None

time = float(input('請輸入工時數量:(請輸入小數)'))

return size,number,time

# 這裡返回的是一個元組

elif choice == '2':

size = float(input('請輸入項目大小:(1代表標準大小,請輸入小數)'))

number = int(input('請輸入人力數量:(請輸入整數)'))

time = None

return size,number,time

# 這裡返回的數據是一個元組

# 完成計算的函數

def estimated(my_input):

# 把元組中的數據取出來

size = my_input[0]

number = my_input[1]

time = my_input[2]

# 人力計算

if (number == None) and (time != None):

number = math.ceil(size * 80 / time)

print('項目大小為%.1f個標準項目,如果需要在%.1f個工時完成,則需要人力數量為:%d人' %(size,time,number))

# 工時計算

elif (number != None) and (time == None):

time = size * 80 / number

print('項目大小為%.1f個標準項目,使用%d個人力完成,則需要工時數量為:%.1f個' %(size,number,time))

# 主函數

def main():

my_input = myinput()

estimated(my_input)

# 調用主函數

main()

之所以寫成“子函數+主函數”的代碼結構,也是因為每個不同的功能封裝在單獨的函數代碼中,方便後續修改、增刪。

比如我們想要加一個功能“讓程序循環運行,直到用戶選擇結束”。那麼,就可以在程序中加上一個again函數。

import math

def myinput():

choice = input('請選擇計算類型:(1-人力計算,2-工時計算)')

if choice == '1':

size = float(input('請輸入項目大小:(1代表標準大小,請輸入小數)'))

number = None

time = float(input('請輸入工時數量:(請輸入小數)'))

return size,number,time

elif choice == '2':

size = float(input('請輸入項目大小:(1代表標準大小,請輸入小數)'))

number = int(input('請輸入人力數量:(請輸入整數)'))

time = None

return size,number,time

def estimated(my_input):

size = my_input[0]

number = my_input[1]

time = my_input[2]

if (number == None) and (time != None):

number = math.ceil(size * 80 / time)

print('項目大小為%.1f個標準項目,如果需要在%.1f個工時完成,則需要人力數量為:%d人' %(size,time,number))

elif (number != None) and (time == None):

time = size * 80 / number

print('項目大小為%.1f個標準項目,使用%d個人力完成,則需要工時數量為:%.1f個' %(size,number,time))

def main():

my_input = myinput()

estimated(my_input)

main()

比如我們想要加一個功能“讓程序循環運行,直到用戶選擇結束”。那麼,就可以在程序中加上一個again函數。

你可以先試試,看是否能夠自己完成這個函數的添加(注:可以複製到本地改造,完成後再複製上來)。

提示:1.需要新增變量和改造主函數;2.用到的知識是判斷和循環;3.對代碼進行調整是正常的(即不要期待總能一次成功)。

看下參考代碼:

python 函數封閉調用

python 函數封閉調用

python 函數封閉調用

python 函數封閉調用

循環運行程序的開關代碼:

import math

# 變量key代表循環運行程序的開關

key = 1

# 採集信息的函數

def myinput():

choice = input('請選擇計算類型:(1-工時計算,2-人力計算)')

if choice == '1':

size = float(input('請輸入項目大小:(1代表標準大小,請輸入小數)'))

number = int(input('請輸入人力數量:(請輸入整數)'))

time = None

return size,number,time

# 這裡返回的數據是一個元組

if choice == '2':

size = float(input('請輸入項目大小:(1代表標準大小,請輸入小數)'))

number = None

time = float(input('請輸入工時數量:(請輸入小數)'))

return size,number,time

# 這裡返回的是一個元組

# 完成計算的函數

def estimated(my_input):

# 把元組中的數據取出來

size = my_input[0]

number = my_input[1]

time = my_input[2]

# 人力計算

if (number == None) and (time != None):

number = math.ceil(size * 80 / time)

print('項目大小為%.1f個標準項目,如果需要在%.1f個工時完成,則需要人力數量為:%d人' %(size,time,number))

# 工時計算

elif (number != None) and (time == None):

time = size * 80 / number

print('項目大小為%.1f個標準項目,使用%d個人力完成,則需要工時數量為:%.1f個' %(size,number,time))

# 詢問是否繼續的函數

def again():

# 聲明全局變量key,以便修改該變量

global key

a = input('是否繼續計算?繼續請輸入y,輸入其他鍵將結束程序。')

if a != 'y':

# 如果用戶不輸入'y',則把key賦值為0

key = 0

# 主函數

def main():

print('歡迎使用工作量計算小程序!')

while key == 1:

my_input = myinput()

estimated(my_input)

again()

print('感謝使用工作量計算小程序!')

main()

到這裡,這一關就要收尾了。在本關我們模擬了“程序員”接“產品經理”需求的過程,開發出了一個迷你產品“工作量計算器”。同時,我們也對函數知識、解決問題的知識做了複習。最後,還給大家展示了“子函數+主函數”的編程結構

不過,隨著我們編寫的代碼規模越大,越容易犯錯。編程中的報錯(俗稱bug)讓人最為惱火,特別是當程序運行不通過而你又定位不到問題的時候。

下一關,我會給你講如何調試(debug,即解決bug)的技巧,讓頭髮少掉,讓痛苦更輕,也更快過去。

練習目標:

我們會通過今天的作業,做出和電腦進行“石頭剪刀布”的遊戲。

練習要求:

和電腦玩一個剪刀石頭布的遊戲:電腦隨機出拳,我們可選擇出什麼。

首先,我們要讓雙方選擇出拳,才能判斷勝負。

我們可以設置變量computer_choice代表電腦的出拳選擇,設置變量user_choice代表你的出拳選擇。

電腦的出拳,我們可以使用random.choice()來隨機選擇;我們的出拳,可以手動輸入我們出拳的類型。

另外,判斷下輸入:當輸入的內容不是石頭剪刀布時,電腦會提醒'輸入有誤,請重新出拳',並重新出拳。

請根據已經設置好的代碼,補充代碼,讓代碼符合上面的要求。

你和電腦已經對自己要出的拳進行了選擇,接下來,我們需要知道雙方的出拳類型。

請使用print()函數補充亮拳的結果。

在前面兩步,電腦和你已經選擇完出拳的類型並亮拳後,只差最後一步:根據結果判斷勝負。

請將代碼補充完整,並運行幾次試試是否正確判斷

import random

# 出拳

punches = ['石頭','剪刀','布']

computer_choice = random.choice(punches)

user_choice = ''

user_choice = input('請出拳:(石頭、剪刀、布)') # 請用戶輸入選擇

while user_choice not in punches: # 當用戶輸入錯誤,提示錯誤,重新輸入

print('輸入有誤,請重新出拳')

user_choice = input()

# 亮拳

print('————戰鬥過程————')

print('電腦出了:%s' % computer_choice)

print('你出了:%s' % user_choice)

# 勝負

print('—————結果—————')

if user_choice == computer_choice: # 使用if進行條件判斷

print('平局!')

elif (user_choice == '石頭' and computer_choice == '剪刀') or (user_choice == '剪刀' and computer_choice == '布') or (user_choice == '布' and computer_choice == '石頭'):

print('你贏了!')

else:

print('你輸了!')

上一個練習的代碼中,有一個判斷語句的代碼很長很長:

elif (user_choice == '石頭' and computer_choice == '剪刀') or (user_choice == '剪刀' and computer_choice == '布') or (user_choice == '布' and computer_choice == '石頭'):

通過一個新的知識,將其簡化,體驗到“知識得增加,代碼得簡化”這個客觀規律。

index() 函數

index() 函數用於找出列表中某個元素第一次出現的索引位置。

語法為:list.index(obj),obj為object(對象)的縮寫。

具體可參考右側的代碼和運行結果。

num = [0,1,0,1,2]

print(num.index(1)) # 數字1首先出現的索引位置是list[1](索引位置從0開始)。

print(num.index(2)) # 數字2首先出現的索引位置是list[4]。

python 函數封閉調用

現在,請你根據新學的函數去簡化代碼吧。

相信你已經完成了代碼的簡化,不過,還是可以再看看參考代碼。

import random

# 出拳

punches = ['石頭','剪刀','布']

computer_choice = random.choice(punches)

user_choice = ''

user_choice = input('請出拳:(石頭、剪刀、布)') # 請用戶輸入選擇

while user_choice not in punches: # 當用戶輸入錯誤,提示錯誤,重新輸入

print('輸入有誤,請重新出拳')

user_choice = input()

# 亮拳

print('————戰鬥過程————')

print('電腦出了:%s' % computer_choice)

print('你出了:%s' % user_choice)

# 勝負

print('—————結果—————')

if user_choice == computer_choice: # 使用if進行條件判斷

print('平局!')

# 電腦的選擇有3種,索引位置分別是:0石頭、1剪刀、2布。

# 假設在電腦索引位置上減1,對應:-1布,0石頭,1剪刀,皆勝。

elif user_choice == punches[punches.index(computer_choice)-1]:

print('你贏了!')

else:

print('你輸了!')


分享到:


相關文章: