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('你输了!')


分享到:


相關文章: