和程序对话

完整讲解 · 9 段教学·配 4 道练习题·预计 50 分钟

本页是本章的通读版,可直接读完全部讲解。想动手写代码、跑判分,去 闯关模式。

教学 01 / 09

前言

学到这里,咱们在前面三章认识了 Python,学会了用 print() 输出,还学了字符串、整数、浮点数这几种基本的数据类型。

不知道各位童鞋有没有这样的感觉:教程里的例子,一个个都看得懂,可一合上教程,让自己从头写个小程序,却不知道该从哪一行写起。

这很正常,每一个学过编程的人都经历过这个阶段。

因为,看懂和会写之间,只隔着一件事:动手。

这就跟学游泳一样,在岸上把动作要领背得再熟,下了水照样要呛几口水。写程序也是这样,例子看十遍,还不如自己敲一遍。敲错了、报错了,再自己改对,这才算真正学会了。

所以从这一章开始,我们会穿插一些「实战」。实战章不急着学新语法,而是用刚学过的知识,做一个真正能用的小东西:记账本。一开始它会很简陋,但那是你亲手写出来的。往后每学完几章,我们就回到这里,给它添一点新本事。

写的过程中,漏个括号、打成中文引号、忘了转换类型,这些都是家常便饭,千万别因为这个就觉得自己不适合学编程。报错并不是在笑话你,它其实是在告诉你,下一步该改哪里。卡住了也没关系,回头再读一遍、再敲一遍,很多时候,第二遍就通了。

学这一章之前,需要先会第 2 章的 print()、字符串、整数、浮点数、类型转换和 f-string,这一章几乎每一节都会用到它们。哪里卡住了,就回到 第 2 章 对应的小节看一看。

目录

这一章会学到:

  • 一、让程序开口问你——用 input() 读取用户的输入
  • 二、12 加 30,怎么等于 1230?——input() 返回的永远是字符串,要用 int() 转换
  • 三、花了 12.5 元怎么记?——用 float() 处理小数,用 :.2f 显示金额
  • 四、不报错,结果却是错的——认识最难发现的一类 bug
  • 五、常见坑
  • 六、自己查一次文档——用 help() 看函数的说明书
  • 七、记账本 v0
  • 八、小结与回看

学完这一章,你会写出记账本的第一个版本:它会问你买了什么、花了多少钱,再帮你把账算清楚。

教学 02 / 09

一、让程序开口问你

到现在为止,咱们写的程序,数据都是提前写死在代码里的。

比如想算一算今天花了多少钱,只能这样写:

Python· 可在网页运行
breakfast = 8
lunch = 25
print(f'今天一共花了 {breakfast + lunch} 元')

输出的结果:

文本
今天一共花了 33 元

今天的账,这样算是算出来了。可是明天早饭花了 10 块呢?难道每天都要打开代码,把数字改一遍?

其实,记账这件事本来应该反过来:程序问我们「花了多少」,我们回答,程序帮着算。这一章就来做这件事:让程序在运行的时候,向使用它的人要数据。

这就是记账本的第一步。

第一次用 input()

那么,怎么让程序开口问人呢?Python 里,让程序停下来等人输入的函数,叫 input() 。先拿问名字来试一试:

Python· 可在网页运行
name = input('你叫什么名字?')
print(f'你好,{name}')
示例输入(每行一个值)
两点水

输出的结果:

文本
你叫什么名字?两点水
你好,两点水

这两行代码是怎么工作的呢?input() 括号里的文字是提示语。程序先把提示语显示出来,然后停下来等。你输入内容、按下回车,输入的内容就成了 input() 的结果,在这里被存进了变量 name 。下一行再把 name 放进问候语里,打印出来。

在自己电脑上运行时,程序会停在「你叫什么名字?」后面,光标一闪一闪地等你打字。

可是在网页里,没法这样边运行边打字。所以带 input() 的代码下面,会多出一个「程序输入」框:运行之前,先把要输入的内容填进去,每行一个值。程序每调用一次 input() ,就按顺序从框里取走一行。输出区会像终端一样,把这一行显示在提示语的后面。

试着把框里的「两点水」改成你自己的名字,再运行一次。

要是框里什么都没填,又会怎么样呢?程序会报 EOFError ,意思是「想读输入,但已经没有内容可读了」。遇到它,去框里补上一行就好。

名字能问了,下一节就让记账本问点正经的:今天花了多少钱。

教学 03 / 09

二、12 加 30,怎么等于 1230?

上一节,程序已经能问名字了。照着同样的写法,记账本也可以问一问花了多少钱。先记两笔试试:

Python· 可在网页运行
a = input('第一笔:')
b = input('第二笔:')
print(a + b)
示例输入(每行一个值)
12
30

输出的结果:

文本
第一笔:12
第二笔:30
1230

12 加 30,怎么等于 1230 ?

这个结果是不是有点眼熟?第 2 章讲类型转换的时候,'100' + '300' 得到的是 100300 。两个字符串相加,并不是算加法,而是把它们拼在一起。

这样一来,问题就变成了:a 和 b 是字符串吗?我们输入的明明是数字啊。

是不是字符串,光靠猜是猜不出来的。用 type() 看一下就知道了:

Python· 可在网页运行
a = input('第一笔:')
print(type(a))
示例输入(每行一个值)
12

输出的结果:

文本
第一笔:12
<class 'str'>

<class 'str'> 说明,a 确实是字符串。所以答案很明确:input() 返回的永远是字符串。不管你输入的是 12、12.5 还是「奶茶」,它都原样交给你一串文字。这串文字是不是数字,要由我们自己来判断,再动手转换。

那怎么转换呢?用第 2 章学过的 int() ,把它们变成整数再相加:

Python· 可在网页运行
a = input('第一笔:')
b = input('第二笔:')
print(int(a) + int(b))
示例输入(每行一个值)
12
30

输出的结果:

文本
第一笔:12
第二笔:30
42

这次对了。

不过,这样写的话,每次用到 a 、b 都得套一层 int() 。其实也可以在读进来的那一刻就转好,后面用起来就不用再操心了:

Python· 可在网页运行
a = int(input('第一笔:'))
b = int(input('第二笔:'))
print(f'合计:{a + b} 元')
示例输入(每行一个值)
12
30

输出的结果:

文本
第一笔:12
第二笔:30
合计:42 元

int(input('第一笔:')) 这种一层套一层的写法,要从里往外读:先执行 input() ,拿到字符串 '12' ;再把它交给 int() ,变成整数 12 。

整数的花销算对了。先做一道练习,把两笔花销加起来,巩固一下。然后下一节再来看看:要是花了 12.5 元,又该怎么记?

练习 1 / 4两笔花销求和

编辑器里已经用 input() 读进了两笔花销。请把它们转成整数相加,打印出合计,格式是:

文本
合计:42 元

「程序输入」框里预填了 12 和 30,运行后完整的输出应该是:

文本
第一笔:12
第二笔:30
合计:42 元

检查答案时还会换几组别的数字,所以要真的去算,不能直接写死 42。

💡 提示(3 条)
  1. input() 返回的是字符串,'12' + '30' 会拼成 '1230'

  2. 先用 int() 转换再相加:int(a) + int(b),再放进 f-string

  3. 完整代码:

    Python
    a = input('第一笔:')
    b = input('第二笔:')
    print(f'合计:{int(a) + int(b)} 元')
在编辑器里写这题,跑判分、看参考答案去闯关页做这题 →
教学 04 / 09

三、花了 12.5 元怎么记?

上一节的记账本,记的都是整数块钱。可买东西不总是整数,比如一杯奶茶就是 12.5 元。拿上面的记账本试一试:

Python· 预期报错示例
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() :

Python· 可在网页运行
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 元:

Python· 可在网页运行
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 ,正好派上用场:

Python· 可在网页运行
a = float(input('第一笔:'))
b = float(input('第二笔:'))
print(f'合计:{a + b:.2f} 元')
示例输入(每行一个值)
12.3
30.1

输出的结果:

文本
第一笔:12.3
第二笔:30.1
合计:42.40 元

这回显示成了 42.40 元,看着就顺眼多了。

不过要注意,:.2f 只改变显示的样子,变量里存的还是那个不精确的数。对记账本来说,这样暂时够用了。真正和钱打交道的程序,会用更严格的办法,比如统一以「分」为单位、用整数来算,等以后用得上时再学。

到这里,整数和小数的花销都能记、能算了。先做一道练习,把两笔带小数的花销加起来。下一节,咱们来看一种更隐蔽的错误:程序不报错,结果却是错的。

练习 2 / 4带小数的花销

这次花销可能带小数。请把两笔花销转成浮点数相加,保留两位小数打印合计:

文本
合计:42.40 元

「程序输入」框里预填了 12.3 和 30.1,运行后完整的输出应该是:

文本
第一笔:12.3
第二笔:30.1
合计:42.40 元

检查答案时还会用 12.5 和 30、0.1 和 0.2 这两组输入。

💡 提示(3 条)
  1. 带小数的字符串不能用 int() 转换,要用 float()

  2. f-string 里写 {total:.2f} 就能保留两位小数

  3. 完整代码:

    Python
    a = input('第一笔:')
    b = input('第二笔:')
    total = float(a) + float(b)
    print(f'合计:{total:.2f} 元')
在编辑器里写这题,跑判分、看参考答案去闯关页做这题 →
教学 05 / 09

四、不报错,结果却是错的

前面两节碰到的问题,要么结果一看就不对,要么程序直接报错,都很容易发现。可还有一种错误,藏得要深得多。

咱们给记账本加一个小功能:每天的预算是 30 元,看看今天是不是刚好花完。

Python· 可在网页运行
budget = 30
spent = input('今天花了多少:')
print(spent == budget)
示例输入(每行一个值)
30

输出的结果:

文本
今天花了多少:30
False

明明输入的就是 30,为什么是 False ?

还是那个老问题:spent 是字符串 '30' ,budget 是整数 30 。在 Python 看来,一段文字和一个数字不是同一种东西,当然不相等。

这个例子最需要留意的地方是:它没有报错。程序安安静静地跑完了,只是给出了一个错误的答案。

那么,要是不比相等,换成比大小呢?这回 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=}" ,把它打印出来看看:

Python· 可在网页运行
spent = input('今天花了多少:')
print(f'{spent=}')
示例输入(每行一个值)
30

输出的结果:

文本
今天花了多少:30
spent='30'

输出里的那对引号说明了一切:'30' 是个字符串。

学会了这一招,先做一道练习,亲手修好这个不报错的 bug。下一节,咱们把用 input() 时最容易踩的几个坑,集中过一遍。

练习 3 / 4修好不报错的 bug

下面的代码想判断今天是不是刚好花完 30 元的预算。可是输入 30 时,它打印的是 False ,而且没有报错。

请只改一处,让输入 30 时打印 True ,输入别的数时打印 False 。

「程序输入」框里预填了 30,改好后运行,完整的输出应该是:

文本
今天花了多少:30
True
💡 提示(3 条)
  1. 先想清楚:spent 现在是字符串还是数字?可以用 print(f'{spent=}') 看一看

  2. 字符串 '30' 和整数 30 永远不相等,要先把 spent 转成数字

  3. 完整代码:

    Python
    budget = 30
    spent = int(input('今天花了多少:'))
    print(spent == budget)
在编辑器里写这题,跑判分、看参考答案去闯关页做这题 →
教学 06 / 09

五、常见坑

input() 用起来并不难,可刚开始用它的时候,有几个坑特别容易踩。下面一个一个来看。

1、把变量起名叫 input

先看一个起名字的坑。有的童鞋觉得,读进来的东西就叫 input ,挺顺手:

Python· 预期报错示例
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元 :

Python· 预期报错示例
cost = float(input('花了多少:'))
示例输入(每行一个值)
12元

报错信息的最后一行是:

文本
ValueError: could not convert string to float: '12元'

float() 只认数字的写法,「元」它不认识,所以没法转换。那怎么办呢?现在我们先和自己约定:记账本只输入数字。等学了条件判断和异常处理,就能让程序自己发现这种输入,客客气气地请用户重新输入。

3、前后多了空格

输入时不小心多敲了空格,会不会出错?

Python· 可在网页运行
cost = float(input('花了多少:'))
print(cost)
示例输入(每行一个值)
  12.5

输出的结果:

文本
花了多少:  12.5
12.5

答案是不会。从输出可以看到,float() 把前面的空格忽略掉了。其实 int() 和 float() 都一样,会自动忽略数字前后的空格。

不过,这只在转换数字的时候成立。如果读进来的是名字这类文字,空格会原样留下来。这时候可以用字符串的 strip() 方法,它能去掉前后的空白。先用起来,后面讲字符串方法时会看到更多:

Python· 可在网页运行
item = input('买了什么:').strip()
print(f'[{item}]')
示例输入(每行一个值)
  奶茶  

输出的结果:

文本
买了什么:  奶茶  
[奶茶]

打印的时候,故意用方括号把 item 括起来,就是为了看清它前后还有没有空格。可以看到,方括号里只剩下「奶茶」了。

4、输入的行数不够

最后一个坑,是在网页里运行时才会碰到的。程序调用几次 input() ,「程序输入」框里就要准备几行。准备少了,会报第一节说过的 EOFError 。准备多了也不要紧,多出来的行不会被读到,也不会报错。

坑踩完了,input() 的用法也就熟得差不多了。不过关于它,还有一些细节没说到,下一节咱们自己去查一查。

教学 07 / 09

六、自己查一次文档

input() 的基本用法已经会了。可它还有哪些脾气呢?比如,提示语后面会不会自动换行?这种问题不用到处去搜,直接问 Python 自己就行。

因为 Python 里的函数都带着说明书,用 help() 就能看:

Python· 可在网页运行
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 。想好了再往下看。

Python· 可在网页运行
item = input('买了什么?\n')
print(f'记下了:{item}')
示例输入(每行一个值)
奶茶

输出的结果:

文本
买了什么?
奶茶
记下了:奶茶

可以看到,提示语末尾加一个 \n ,输入就换到了下一行。

以后遇到不熟悉的函数,先 help() 一下,再动手试一试。这比到处搜答案更快,也更可靠。

工具都备齐了,下一节,咱们把这一章学到的东西串起来,写出记账本的第一个版本。

教学 08 / 09

七、记账本 v0

这一章学了 input() 、float() 和 :.2f ,现在把它们串起来,记账本的第一个版本就是这样的:

Python· 可在网页运行
item = input('买了什么:')
cost = float(input('花了多少钱:'))
print(f'记下了:{item},{cost:.2f} 元')
示例输入(每行一个值)
奶茶
12.5

输出的结果:

文本
买了什么:奶茶
花了多少钱:12.5
记下了:奶茶,12.50 元

别看只有三行代码,这一章的内容全用上了:

  • 第一行用 input() 读入买了什么,拿到的是一串文字。
  • 第二行先用 input() 读入金额,再用 float() 把它变成数字。
  • 第三行用 f-string 把两样拼成一句话,金额加上 :.2f ,显示成两位小数。

当然,它现在还很简陋:一次只能记一笔,而且程序一结束,记过的账也就忘了。别急,这些正是后面几个实战章要解决的问题。

现在,先来做本章最后一道题:让记账本一次记两笔。

练习 4 / 4记账本 v0:一次记两笔

让记账本一次记两笔账。每一笔都先问「买了什么:」,再问「花了多少钱:」,最后用一行打印两笔的明细和合计,金额都保留两位小数。

「程序输入」框里预填了奶茶、12.5、午饭、25,运行后完整的输出应该是:

文本
买了什么:奶茶
花了多少钱:12.5
买了什么:午饭
花了多少钱:25
奶茶 12.50 元,午饭 25.00 元,一共 37.50 元

注意最后一行的标点:两笔之间、合计之前用的是中文逗号「,」。

💡 提示(3 条)
  1. 一共要调用 4 次 input():名称、金额、名称、金额,顺序和程序输入框里的 4 行一一对应

  2. 金额用 float(input('花了多少钱:')) 读进来;三个金额都写成 {x:.2f}

  3. 完整代码:

    Python
    item1 = input('买了什么:')
    cost1 = float(input('花了多少钱:'))
    item2 = input('买了什么:')
    cost2 = float(input('花了多少钱:'))
    print(f'{item1} {cost1:.2f} 元,{item2} {cost2:.2f} 元,一共 {cost1 + cost2:.2f} 元')
在编辑器里写这题,跑判分、看参考答案去闯关页做这题 →
教学 09 / 09

八、小结与回看

这一章,程序第一次「听」到了用户的话。回头梳理一下,学到了这几件事:

  • input('提示语') 先显示提示语,再读入一行,返回的永远是字符串。
  • 要当数字用,就自己转换:整数用 int() ,带小数的钱用 float() 。
  • 字符串和数字比大小会报错,比相等却不会报错,只是结果永远是 False 。这种不报错的 bug 最难发现,拿不准的时候,就用 f"{x=}" 打印出来看看。
  • 显示金额时,用 :.2f 保留两位小数。
  • 碰到不熟悉的函数,先用 help() 看看说明书。

哪里卡住了,就回到第 2 章看对应的小节:

  • 字符串相加为什么是拼接:「五、基本数据类型转换」
  • 浮点数为什么算不准:「三、Python 的基本数据类型」里的浮点数
  • f-string 和 :.2f :「三、Python 的基本数据类型」里的 f-string

回头看看,记账本 v0 只有短短几行,却是你从零开始、自己写出来的第一个能用的程序。别小看它:从这一章起,你写的程序不再只会自说自话,它开始听你说话了。

不过,现在的记账本只能记一两笔。要记下一整天、一整个月的账,就需要一个能装下很多笔的容器,还要让程序一遍一遍地问下去。这些本事,接下来的第 3~5 章会讲到,也就是列表、字典和循环。学完之后,咱们在实战 2 里把记账本升级到 v1。

读完了?动手练一遍才算真会。

去闯关模式练习 →

学习目录