和程序对话
完整讲解 · 9 段教学·配 4 道练习题·预计 50 分钟
本页是本章的通读版,可直接读完全部讲解。想动手写代码、跑判分,去 闯关模式。
前言
学到这里,咱们在前面三章认识了 Python,学会了用 print() 输出,还学了字符串、整数、浮点数这几种基本的数据类型。
不知道各位童鞋有没有这样的感觉:教程里的例子,一个个都看得懂,可一合上教程,让自己从头写个小程序,却不知道该从哪一行写起。
这很正常,每一个学过编程的人都经历过这个阶段。
因为,看懂和会写之间,只隔着一件事:动手。
这就跟学游泳一样,在岸上把动作要领背得再熟,下了水照样要呛几口水。写程序也是这样,例子看十遍,还不如自己敲一遍。敲错了、报错了,再自己改对,这才算真正学会了。
所以从这一章开始,我们会穿插一些「实战」。实战章不急着学新语法,而是用刚学过的知识,做一个真正能用的小东西:记账本。一开始它会很简陋,但那是你亲手写出来的。往后每学完几章,我们就回到这里,给它添一点新本事。
写的过程中,漏个括号、打成中文引号、忘了转换类型,这些都是家常便饭,千万别因为这个就觉得自己不适合学编程。报错并不是在笑话你,它其实是在告诉你,下一步该改哪里。卡住了也没关系,回头再读一遍、再敲一遍,很多时候,第二遍就通了。
学这一章之前,需要先会第 2 章的 print()、字符串、整数、浮点数、类型转换和 f-string,这一章几乎每一节都会用到它们。哪里卡住了,就回到 第 2 章 对应的小节看一看。
目录
这一章会学到:
- 一、让程序开口问你——用
input()读取用户的输入 - 二、12 加 30,怎么等于 1230?——
input()返回的永远是字符串,要用int()转换 - 三、花了 12.5 元怎么记?——用
float()处理小数,用:.2f显示金额 - 四、不报错,结果却是错的——认识最难发现的一类 bug
- 五、常见坑
- 六、自己查一次文档——用
help()看函数的说明书 - 七、记账本 v0
- 八、小结与回看
学完这一章,你会写出记账本的第一个版本:它会问你买了什么、花了多少钱,再帮你把账算清楚。
一、让程序开口问你
到现在为止,咱们写的程序,数据都是提前写死在代码里的。
比如想算一算今天花了多少钱,只能这样写:
breakfast = 8
lunch = 25
print(f'今天一共花了 {breakfast + lunch} 元')输出的结果:
今天一共花了 33 元今天的账,这样算是算出来了。可是明天早饭花了 10 块呢?难道每天都要打开代码,把数字改一遍?
其实,记账这件事本来应该反过来:程序问我们「花了多少」,我们回答,程序帮着算。这一章就来做这件事:让程序在运行的时候,向使用它的人要数据。
这就是记账本的第一步。
第一次用 input()
那么,怎么让程序开口问人呢?Python 里,让程序停下来等人输入的函数,叫 input() 。先拿问名字来试一试:
name = input('你叫什么名字?')
print(f'你好,{name}')两点水
输出的结果:
你叫什么名字?两点水
你好,两点水这两行代码是怎么工作的呢?input() 括号里的文字是提示语。程序先把提示语显示出来,然后停下来等。你输入内容、按下回车,输入的内容就成了 input() 的结果,在这里被存进了变量 name 。下一行再把 name 放进问候语里,打印出来。
在自己电脑上运行时,程序会停在「你叫什么名字?」后面,光标一闪一闪地等你打字。
可是在网页里,没法这样边运行边打字。所以带 input() 的代码下面,会多出一个「程序输入」框:运行之前,先把要输入的内容填进去,每行一个值。程序每调用一次 input() ,就按顺序从框里取走一行。输出区会像终端一样,把这一行显示在提示语的后面。
试着把框里的「两点水」改成你自己的名字,再运行一次。
要是框里什么都没填,又会怎么样呢?程序会报 EOFError ,意思是「想读输入,但已经没有内容可读了」。遇到它,去框里补上一行就好。
名字能问了,下一节就让记账本问点正经的:今天花了多少钱。
二、12 加 30,怎么等于 1230?
上一节,程序已经能问名字了。照着同样的写法,记账本也可以问一问花了多少钱。先记两笔试试:
a = input('第一笔:')
b = input('第二笔:')
print(a + b)12 30
输出的结果:
第一笔:12
第二笔:30
123012 加 30,怎么等于 1230 ?
这个结果是不是有点眼熟?第 2 章讲类型转换的时候,'100' + '300' 得到的是 100300 。两个字符串相加,并不是算加法,而是把它们拼在一起。
这样一来,问题就变成了:a 和 b 是字符串吗?我们输入的明明是数字啊。
是不是字符串,光靠猜是猜不出来的。用 type() 看一下就知道了:
a = input('第一笔:')
print(type(a))12
输出的结果:
第一笔:12
<class 'str'><class 'str'> 说明,a 确实是字符串。所以答案很明确:input() 返回的永远是字符串。不管你输入的是 12、12.5 还是「奶茶」,它都原样交给你一串文字。这串文字是不是数字,要由我们自己来判断,再动手转换。
那怎么转换呢?用第 2 章学过的 int() ,把它们变成整数再相加:
a = input('第一笔:')
b = input('第二笔:')
print(int(a) + int(b))12 30
输出的结果:
第一笔:12
第二笔:30
42这次对了。
不过,这样写的话,每次用到 a 、b 都得套一层 int() 。其实也可以在读进来的那一刻就转好,后面用起来就不用再操心了:
a = int(input('第一笔:'))
b = int(input('第二笔:'))
print(f'合计:{a + b} 元')12 30
输出的结果:
第一笔:12
第二笔:30
合计:42 元int(input('第一笔:')) 这种一层套一层的写法,要从里往外读:先执行 input() ,拿到字符串 '12' ;再把它交给 int() ,变成整数 12 。
整数的花销算对了。先做一道练习,把两笔花销加起来,巩固一下。然后下一节再来看看:要是花了 12.5 元,又该怎么记?
编辑器里已经用 input() 读进了两笔花销。请把它们转成整数相加,打印出合计,格式是:
合计:42 元「程序输入」框里预填了 12 和 30,运行后完整的输出应该是:
第一笔:12
第二笔:30
合计:42 元检查答案时还会换几组别的数字,所以要真的去算,不能直接写死 42。
💡 提示(3 条)
input() 返回的是字符串,'12' + '30' 会拼成 '1230'
先用 int() 转换再相加:int(a) + int(b),再放进 f-string
完整代码:
a = input('第一笔:') b = input('第二笔:') print(f'合计:{int(a) + int(b)} 元')
三、花了 12.5 元怎么记?
上一节的记账本,记的都是整数块钱。可买东西不总是整数,比如一杯奶茶就是 12.5 元。拿上面的记账本试一试:
a = int(input('第一笔:'))
b = int(input('第二笔:'))
print(f'合计:{a + b} 元')12.5 30
程序在第一笔就停下了,报错信息的最后一行是:
ValueError: invalid literal for int() with base 10: '12.5'为什么会这样呢?第 2 章说过,小数形式的字符串,不能用 int() 转换。所以带小数的钱,要换成 float() :
a = float(input('第一笔:'))
b = float(input('第二笔:'))
print(f'合计:{a + b} 元')12.5 30
输出的结果:
第一笔:12.5
第二笔:30
合计:42.5 元可以看到,第二笔输入的是 30,float('30') 得到 30.0 ,照样能算。既然整数、小数它都能对付,那记钱的时候,统一用 float() 更省心。
小数是能算了,可每次都会这么顺利吗?再换两笔试试,12.3 元和 30.1 元:
a = float(input('第一笔:'))
b = float(input('第二笔:'))
print(f'合计:{a + b} 元')12.3 30.1
输出的结果:
第一笔:12.3
第二笔:30.1
合计:42.400000000000006 元又是这样一串长长的小数。第 2 章讲浮点数的时候已经见过它:计算机保存小数,本来就不精确。算出来的结果和真正的 42.4 只差了一点点,可要是直接拿给人看,就很别扭。
那该怎么办呢?钱一般只算到分,也就是保留两位小数。第 2 章 f-string 一节讲过的 :.2f ,正好派上用场:
a = float(input('第一笔:'))
b = float(input('第二笔:'))
print(f'合计:{a + b:.2f} 元')12.3 30.1
输出的结果:
第一笔:12.3
第二笔:30.1
合计:42.40 元这回显示成了 42.40 元,看着就顺眼多了。
不过要注意,:.2f 只改变显示的样子,变量里存的还是那个不精确的数。对记账本来说,这样暂时够用了。真正和钱打交道的程序,会用更严格的办法,比如统一以「分」为单位、用整数来算,等以后用得上时再学。
到这里,整数和小数的花销都能记、能算了。先做一道练习,把两笔带小数的花销加起来。下一节,咱们来看一种更隐蔽的错误:程序不报错,结果却是错的。
这次花销可能带小数。请把两笔花销转成浮点数相加,保留两位小数打印合计:
合计:42.40 元「程序输入」框里预填了 12.3 和 30.1,运行后完整的输出应该是:
第一笔:12.3
第二笔:30.1
合计:42.40 元检查答案时还会用 12.5 和 30、0.1 和 0.2 这两组输入。
💡 提示(3 条)
带小数的字符串不能用 int() 转换,要用 float()
f-string 里写 {total:.2f} 就能保留两位小数
完整代码:
a = input('第一笔:') b = input('第二笔:') total = float(a) + float(b) print(f'合计:{total:.2f} 元')
四、不报错,结果却是错的
前面两节碰到的问题,要么结果一看就不对,要么程序直接报错,都很容易发现。可还有一种错误,藏得要深得多。
咱们给记账本加一个小功能:每天的预算是 30 元,看看今天是不是刚好花完。
budget = 30
spent = input('今天花了多少:')
print(spent == budget)30
输出的结果:
今天花了多少:30
False明明输入的就是 30,为什么是 False ?
还是那个老问题:spent 是字符串 '30' ,budget 是整数 30 。在 Python 看来,一段文字和一个数字不是同一种东西,当然不相等。
这个例子最需要留意的地方是:它没有报错。程序安安静静地跑完了,只是给出了一个错误的答案。
那么,要是不比相等,换成比大小呢?这回 Python 倒是会直接报错:
budget = 30
spent = input('今天花了多少:')
print(spent > budget)30
报错信息的最后一行是:
TypeError: '>' not supported between instances of 'str' and 'int'把这两个例子放在一起比一比,就能看出差别了。报错的 bug,程序会停下来告诉你问题出在哪里,反而好找。不报错的 bug,结果悄悄地错了,可能很久都没人发现。
所以,拿 input() 读进来的值去计算、比较之前,先问自己一句:它现在是字符串,还是数字?
可要是拿不准呢?那就用第 2 章讲过的 f"{x=}" ,把它打印出来看看:
spent = input('今天花了多少:')
print(f'{spent=}')30
输出的结果:
今天花了多少:30
spent='30'输出里的那对引号说明了一切:'30' 是个字符串。
学会了这一招,先做一道练习,亲手修好这个不报错的 bug。下一节,咱们把用 input() 时最容易踩的几个坑,集中过一遍。
下面的代码想判断今天是不是刚好花完 30 元的预算。可是输入 30 时,它打印的是 False ,而且没有报错。
请只改一处,让输入 30 时打印 True ,输入别的数时打印 False 。
「程序输入」框里预填了 30,改好后运行,完整的输出应该是:
今天花了多少:30
True💡 提示(3 条)
先想清楚:spent 现在是字符串还是数字?可以用 print(f'{spent=}') 看一看
字符串 '30' 和整数 30 永远不相等,要先把 spent 转成数字
完整代码:
budget = 30 spent = int(input('今天花了多少:')) print(spent == budget)
五、常见坑
input() 用起来并不难,可刚开始用它的时候,有几个坑特别容易踩。下面一个一个来看。
1、把变量起名叫 input
先看一个起名字的坑。有的童鞋觉得,读进来的东西就叫 input ,挺顺手:
input = input('第一笔:')
b = input('第二笔:')12 30
运行一下,第一笔顺利读进来了,第二笔却报错了,报错信息的最后一行是:
TypeError: 'str' object is not callable为什么呢?
第一行执行完,input 这个名字就不再指向那个能读输入的函数,而是指向了字符串 '12' 。第二行再「调用」input(...) ,就相当于去调用一个字符串,Python 当然做不到。
解决的办法很简单:变量换个名字,比如 first 、cost 。print 、input 、int 、str 这些 Python 已经占用的名字,都不要拿来当变量名。
2、输入里带了单位
记账的时候,很多人会顺手把单位也打上,比如输入的是 12元 :
cost = float(input('花了多少:'))12元
报错信息的最后一行是:
ValueError: could not convert string to float: '12元'float() 只认数字的写法,「元」它不认识,所以没法转换。那怎么办呢?现在我们先和自己约定:记账本只输入数字。等学了条件判断和异常处理,就能让程序自己发现这种输入,客客气气地请用户重新输入。
3、前后多了空格
输入时不小心多敲了空格,会不会出错?
cost = float(input('花了多少:'))
print(cost)12.5
输出的结果:
花了多少: 12.5
12.5答案是不会。从输出可以看到,float() 把前面的空格忽略掉了。其实 int() 和 float() 都一样,会自动忽略数字前后的空格。
不过,这只在转换数字的时候成立。如果读进来的是名字这类文字,空格会原样留下来。这时候可以用字符串的 strip() 方法,它能去掉前后的空白。先用起来,后面讲字符串方法时会看到更多:
item = input('买了什么:').strip()
print(f'[{item}]')奶茶
输出的结果:
买了什么: 奶茶
[奶茶]打印的时候,故意用方括号把 item 括起来,就是为了看清它前后还有没有空格。可以看到,方括号里只剩下「奶茶」了。
4、输入的行数不够
最后一个坑,是在网页里运行时才会碰到的。程序调用几次 input() ,「程序输入」框里就要准备几行。准备少了,会报第一节说过的 EOFError 。准备多了也不要紧,多出来的行不会被读到,也不会报错。
坑踩完了,input() 的用法也就熟得差不多了。不过关于它,还有一些细节没说到,下一节咱们自己去查一查。
六、自己查一次文档
input() 的基本用法已经会了。可它还有哪些脾气呢?比如,提示语后面会不会自动换行?这种问题不用到处去搜,直接问 Python 自己就行。
因为 Python 里的函数都带着说明书,用 help() 就能看:
help(input)说明书的主要内容是这样的(开头一行在不同环境里略有差别):
input(prompt='', /)
Read a string from standard input. The trailing newline is stripped.
The prompt string, if given, is printed to standard output without a
trailing newline before reading input.
If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
On *nix systems, readline is used if available.是英文的,别怕。咱们挑要紧的,一句一句地看:
- 第一句:从标准输入读取一个字符串,末尾的换行会被去掉。所以拿到的永远是字符串,而且不带回车。
- 第二句:如果给了提示语,会在读取之前先输出它,后面不加换行。所以输入的内容会紧跟在提示语后面。
- 第三句:遇到 EOF(输入结束)就抛出
EOFError。这就是「程序输入」框空了时看到的那个报错。
要是英文读着实在吃力,官方文档里也有同样内容的中文版:内置函数 input() 。
读懂了,现在来动手用一用。说明书里说「提示语后面不加换行」,那么,如果想让用户在提示语的下一行输入,提示语该怎么写?
提示一下:换行符 \n 。想好了再往下看。
item = input('买了什么?\n')
print(f'记下了:{item}')奶茶
输出的结果:
买了什么?
奶茶
记下了:奶茶可以看到,提示语末尾加一个 \n ,输入就换到了下一行。
以后遇到不熟悉的函数,先 help() 一下,再动手试一试。这比到处搜答案更快,也更可靠。
工具都备齐了,下一节,咱们把这一章学到的东西串起来,写出记账本的第一个版本。
七、记账本 v0
这一章学了 input() 、float() 和 :.2f ,现在把它们串起来,记账本的第一个版本就是这样的:
item = input('买了什么:')
cost = float(input('花了多少钱:'))
print(f'记下了:{item},{cost:.2f} 元')奶茶 12.5
输出的结果:
买了什么:奶茶
花了多少钱:12.5
记下了:奶茶,12.50 元别看只有三行代码,这一章的内容全用上了:
- 第一行用
input()读入买了什么,拿到的是一串文字。 - 第二行先用
input()读入金额,再用float()把它变成数字。 - 第三行用 f-string 把两样拼成一句话,金额加上
:.2f,显示成两位小数。
当然,它现在还很简陋:一次只能记一笔,而且程序一结束,记过的账也就忘了。别急,这些正是后面几个实战章要解决的问题。
现在,先来做本章最后一道题:让记账本一次记两笔。
让记账本一次记两笔账。每一笔都先问「买了什么:」,再问「花了多少钱:」,最后用一行打印两笔的明细和合计,金额都保留两位小数。
「程序输入」框里预填了奶茶、12.5、午饭、25,运行后完整的输出应该是:
买了什么:奶茶
花了多少钱:12.5
买了什么:午饭
花了多少钱:25
奶茶 12.50 元,午饭 25.00 元,一共 37.50 元注意最后一行的标点:两笔之间、合计之前用的是中文逗号「,」。
💡 提示(3 条)
一共要调用 4 次 input():名称、金额、名称、金额,顺序和程序输入框里的 4 行一一对应
金额用 float(input('花了多少钱:')) 读进来;三个金额都写成 {x:.2f}
完整代码:
item1 = input('买了什么:') cost1 = float(input('花了多少钱:')) item2 = input('买了什么:') cost2 = float(input('花了多少钱:')) print(f'{item1} {cost1:.2f} 元,{item2} {cost2:.2f} 元,一共 {cost1 + cost2:.2f} 元')
八、小结与回看
这一章,程序第一次「听」到了用户的话。回头梳理一下,学到了这几件事:
input('提示语')先显示提示语,再读入一行,返回的永远是字符串。- 要当数字用,就自己转换:整数用
int(),带小数的钱用float()。 - 字符串和数字比大小会报错,比相等却不会报错,只是结果永远是
False。这种不报错的 bug 最难发现,拿不准的时候,就用f"{x=}"打印出来看看。 - 显示金额时,用
:.2f保留两位小数。 - 碰到不熟悉的函数,先用
help()看看说明书。
哪里卡住了,就回到第 2 章看对应的小节:
- 字符串相加为什么是拼接:「五、基本数据类型转换」
- 浮点数为什么算不准:「三、Python 的基本数据类型」里的浮点数
- f-string 和
:.2f:「三、Python 的基本数据类型」里的 f-string
回头看看,记账本 v0 只有短短几行,却是你从零开始、自己写出来的第一个能用的程序。别小看它:从这一章起,你写的程序不再只会自说自话,它开始听你说话了。
不过,现在的记账本只能记一两笔。要记下一整天、一整个月的账,就需要一个能装下很多笔的容器,还要让程序一遍一遍地问下去。这些本事,接下来的第 3~5 章会讲到,也就是列表、字典和循环。学完之后,咱们在实战 2 里把记账本升级到 v1。
读完了?动手练一遍才算真会。
去闯关模式练习 →