同一个加号,两边都是字符串就拼接,两边都是数字就求和,一边一样就报错。
input() 拿到的永远是字符串。该算数的地方忘了转,程序不会报错,它会把 21 变成 2121。
f-string 是拼输出的正路;但中文用它也对不齐,因为宽度是按字符数算的,一个汉字占两格。
上一篇学了 if 怎么改变走向,这一篇处理数据本身:字符串怎么切、类型怎么转、输出怎么排。 教材第 2 章后三节是【处理字符串数据】【字符串处理与数据类型转换】【格式化字符串】。 这三节是全书出现频率最高的内容。后面每一章都在拼字符串、转数字、打印结果。 本篇有个反直觉的结论要提前说: 官方文档说 f-string 能对齐,中文它也对不齐。演示里两种写法都摆了,你能看到两只手一起歪。
一、加号的两副面孔
'3' + '4' 得 '34',3 + 4 得 7。同一个符号,两种意思:拼接和求和。
决定用哪种的不是符号,是两边的类型。两边都是字符串就接起来,两边都是数字就加起来。
一边字符串一边数字呢?Python 不猜,直接报错:can only concatenate str (not "int") to str。
这条报错信息值得读一遍:它没说「类型不对」,它说「只能把字符串接到字符串上」。 把错误信息读明白,比背语法有用。
二、转换:三个函数管三种去向
int() 去整数,float() 去小数,str() 去文字。三个函数,解决九成的类型问题。
有一个坑必须知道:int('3.5') 报错。因为 int() 只认「纯整数的写法」,它不负责解析小数点。
要转得绕一下:int(float('3.5')),先变 3.5 再截成 3。
注意是截断不是四舍五入,int(3.9) 也是 3。
反过来,str(3.9) 得到 '3.9',不丢精度。
float('3') 得到 3.0,整数转小数永远无损,小数转整数永远有损。
还有一个反直觉的:int() 能吃掉首尾空格,int(' 42 ') 是 42。
但它吃不下千分位逗号,int('1,000') 直接报错,得先 replace(',', '')。
三、input 拿到的一定是字符串
演示第三段是全书最该记住的一个坑。
程序想算 21 + 21,但 input() 给的是字符串 '21',加号于是做了拼接,输出 2121。
它不报错,它给你一个看起来很合理的错答案。 这类错误比报错难查十倍。
规矩只有一条:input() 的返回值,在拿去算之前必须转。n = int(input('几件?')),一行解决。
如果用户可能输入非数字,int() 会抛 ValueError。
第 5 章讲 try except 时会处理这个,现在先知道它会炸就行。
四、格式化:三种写法,一种推荐
| 写法 | 代码 | 什么时候用 |
|---|---|---|
| f-string | f"{v:.2f}" |
新代码一律用它 |
format |
"{:.2f}".format(v) |
读老代码时要认得出 |
| 百分号 | '%.2f' % v |
只在看旧教程时遇到 |
三种算出来的结果完全一样。
f-string 好在变量名直接写在花括号里,
不用数后面有几个占位符——占位符和参数的顺序错位,是百分号写法最常见的 bug。
冒号后面那段叫格式说明,几个常用记号得记住:< 左对齐、> 右对齐、^ 居中、数字是宽度、
,.2f 是千分位加两位小数。
例:f"{price:>8,.2f}" 意思是「右对齐、占 8 格、带千分位、两位小数」。
五、中文为什么对不齐
演示里同一张表用百分号和 f-string 各写一遍,结果列位置一模一样,也都歪。 原因不在写法,在「宽度」这条规矩: 格式说明里的宽度按字符个数算,一个汉字算一个字符;但屏幕上它占两格宽。 所以「螺丝」两个字按宽度算占 2,实际显示占 4,后面就少了两格,整列往左偏。
想真对齐只有两条路:按显示宽度自己补空格(一个汉字补两个), 或者干脆交给表格语法(本课的笔记就是用表格排的)。 日常打日志不必纠结。为了对齐把代码写复杂,是本末倒置。
六、字符串的几个常用方法
演示最后一段用的是同一条脏数据:' 2026-11-02, 库存告警, 螺丝只剩3个 '。
| 方法 | 做什么 | 结果 |
|---|---|---|
strip() |
去掉首尾空白 | '2026-11-02, 库存告警, 螺丝只剩3个' |
split(',') |
按分隔符切成列表 | 三段,后两段前面还带空格 |
replace(a, b) |
换掉全部 a | 把「螺丝」换成「膨胀螺栓」 |
startswith(s) |
是不是以 s 开头 | True |
len(s) |
有几个字符 | 28 |
split 有一个容易漏的细节:它不会顺手去空格。 用 , 切,切出来的第二段开头还带着一个空格。
两条路解决:切完每段 strip() 一次,或者干脆写 split(', ') 把空格含进分隔符。
后者更短,但如果有的地方逗号后没空格,就会切不开。
join 是 split 的反向操作:', '.join(['a', 'b']) 得 'a, b'。
注意它是「用谁去连」,所以 join 写在分隔符上,不写在列表上。
七、动手 Demo:字符串、数字、格式化:三种类型三条规矩
先摆清加号的两副面孔,再看三种转换函数各自认什么。
然后复现那个最坑的 2121。
最后把同一张表用百分号和 f-string 各排一遍,看中文到底歪在哪。
print('① 加号对字符串是拼接,对数字是求和')
print(" '3' + '4' =", repr('3' + '4'))
print(' 3 + 4 =', 3 + 4)
try:
'3' + 4
except TypeError as e:
print(' \'3\' + 4 = 报错', e)
print('② 要混着算,先转类型')
print(' int(\'3\') + 4 =', int('3') + 4)
print(' str(3) + \'4\' =', repr(str(3) + '4'))
print(' float(\'3.5\') * 2 =', float('3.5') * 2)
try:
int('3.5')
except ValueError as e:
print(' int(\'3.5\') = 报错', e)
print(' int(float(\'3.5\')) =', int(float('3.5')))
print('③ 输入进来的东西永远是字符串')
raw = input('请输入一个数:')
print(' 输入 %s → %s %r %s' % (raw, type(raw).__name__, raw, raw + raw))
print(' 转一下 →', int(raw) + int(raw))
print('④ 对齐输出:两种写法对比')
items = [('螺丝', 3, 4.5), ('扳手', 12, 288.0), ('电钻', 1, 399.0)]
print(' 用百分号写:')
print(' %-8s %6s %12s' % ('品名', '数量', '金额'))
for n, q, p in items:
print(' %-8s %6d %12.2f' % (n, q, p))
print()
print(' 用 f-string 写同一张表:')
print(' %-8s %6s %12s' % ('品名', '数量', '金额'))
for n, q, p in items:
print(f' {n:<8}{q:>6}{p:>12,.2f}')
print('⑤ 三种格式化写法对照')
v = 3.14159
print(' f-string ' + f'{v:.2f}')
print(' format ' + '{:.2f}'.format(v))
print(' 百分号 ' + '%.2f' % v)
print('⑥ 常用的字符串方法')
s = ' 2026-11-02, 库存告警, 螺丝只剩3个 '
print(' 原串 ', repr(s))
print(' strip ', repr(s.strip()))
print(' split ', s.strip().split(','))
print(' replace', repr(s.strip().replace('螺丝', '膨胀螺栓')))
print(' startswith', s.strip().startswith('2026'), '→', s.strip().startswith('2026'))
print(' len ', len(s))
实跑输出:
--------------------------------------------------------------------
字符串、数字、格式化:三种类型三条规矩
--------------------------------------------------------------------
① 加号对字符串是拼接,对数字是求和
--------------------------------------------------------------------
'3' + '4' = '34'
3 + 4 = 7
'3' + 4 = 报错 can only concatenate str (not "int") to str
同是加号,两边都是字符串就拼接,两边都是数字就求和,一边一样就报错。Python 不会替你猜。
② 要混着算,先转类型
--------------------------------------------------------------------
int('3') + 4 = 7
str(3) + '4' = '34'
float('3.5') * 2 = 7.0
int('3.5') = 报错 invalid literal for int() with base 10: '3.5'
int() 只认纯整数写法。
'3.5' 要先 float() 再 int(),或者 int(float('3.5')),结果会截掉小数变成 3。
③ 输入进来的东西永远是字符串
--------------------------------------------------------------------
输入 21 → str '21' 2121
该求和的地方它把 21 重复了两遍。
这是新手最常见的第一个坑:input() 拿到的是 str,算数前必须 int()。
④ f-string 是对齐输出的正路
--------------------------------------------------------------------
用百分号写:
品名 数量 金额
螺丝 3 4.50
扳手 12 288.00
电钻 1 399.00
用 f-string 写同一张表:
品名 数量 金额
螺丝 3 4.50
扳手 12 288.00
电钻 1 399.00
冒号后面是格式说明:< 左对齐、> 右对齐、8 是宽度、,.2f 是千分位加两位小数。
百分号那套的 %-8s、%6d、%12s 是一回事,只是写法更老。
两种写法算出来的列位置完全一样,也都歪。
说明问题不在写法,而在「宽度按字符算」这条规矩——一个汉字算一格,屏幕上却占两格。
想真对齐只有两条路:按显示宽度自己补空格,或者交给表格语法。
日常打印日志不必纠结这个,别为了对齐把代码写复杂。
⑤ 三种格式化写法对照
--------------------------------------------------------------------
| 写法 | 代码 | 结果 |
|---|---|---|
| f-string | f"{v:.2f}" | 3.14 |
| format | "{:.2f}".format(v) | 3.14 |
| 百分号 | '%.2f' % v | 3.14 |
三种都能用,f-string 最直白:变量名直接写在花括号里,不用数后面有几个占位符。新代码优先用它。
⑥ 常用的字符串方法
--------------------------------------------------------------------
原串 ' 2026-11-02, 库存告警, 螺丝只剩3个 '
strip '2026-11-02, 库存告警, 螺丝只剩3个'
split ['2026-11-02', ' 库存告警', ' 螺丝只剩3个']
replace '2026-11-02, 库存告警, 膨胀螺栓只剩3个'
startswith '2026' → True
len 28
strip 去掉首尾空白,split 按分隔符切成列表,join 反过来把列表拼成串。
注意 split 不会顺手去空格,切出来的第二段前面还带着一个空格——要么切完再 strip,
要么写 split(', ') 把分隔符本身含进去。
第一段三行连起来看:同样是加号,两边都是字符串就拼接,一边一样就报错。 Python 不会替你猜「你是想拼还是想加」,它只会拒绝。 第二段那个 int('3.5') 报错,是新手第二个高频坑。int() 只认纯整数写法,带小数点得先 float()。 注意 int(float('3.5')) 得 3,是截断不是四舍五入。 第三段是本篇的重点。输入 21,输出 2121——它把 21 重复了两遍。程序没报错,只是算错了。这种错最难查。 第四段两张表列位置完全一样,也都歪。 说明问题不在写法,而在宽度按字符数算:一个汉字算一格,屏幕上占两格。 第六段的 split 结果里,后两段前面还带着空格。 split 不会顺手去空格,要么切完再 strip,要么把分隔符写成逗号加空格。
30 秒实验
- 把演示第四段的
{n:<8}改成{n:<10},看列位置往哪挪,验证宽度是按字符数算的。 - 把演示第二段的
int(float('3.5'))改成round(float('3.5')), 再试round(4.5)和round(3.5),看 Python 的「四舍六入五成双」是怎么表现的。 - 把演示第六段的
split(',')改成split(', '),看切出来的第二段前面还有没有空格。
常见误区
- 「加号就是加法。」对字符串它是拼接。 决定用哪种意思的是两边的类型,不是符号。一边一样 Python 直接报错,不会替你猜。
- 「
int()能把'3.5'转成 3。」它直接报错。int()不解析小数点,得先float()。 而且int()是截断,不是四舍五入。 - 「f-string 能对齐中文,比百分号强。」两种写法算出来一模一样,也都歪。 宽度按字符数算,一个汉字算一格,屏幕上占两格,这是格式说明管不到的地方。
自测三问(点开对答案)
1. `'3' + 4` 为什么报错,而 `int('3') + 4` 就没问题? —— 因为加号要求两边同类型:两边都是字符串就拼接,两边都是数字就求和。 `'3'` 是字符串、`4` 是整数,Python 不猜你想干什么,直接拒绝。 `int('3')` 先把字符串变成数字 3,两边就都是数字了。 2. 用户输入 21,程序想算两倍,结果打印出 2121。哪里错了? —— `input()` 返回的是字符串 `'21'`,`'21' + '21'` 做的是拼接,不是加法。 要写成 `int(input(...)) * 2`。**这类错误不报错,只给错答案,最难查。** 3. 用 f-string 写 `{name:<8}`,名字是「螺丝」两个字,为什么后面还是没对齐? —— 因为宽度按字符个数算。「螺丝」是两个字符,`:<8` 会补 6 个空格; 但屏幕上两个字占四格宽,视觉上一共占了 10 格,比按宽度算的 8 格多两格。 **字符数和显示宽度不是一回事。**下一篇进入第 3 章:一次要处理很多笔数据时,列表和循环怎么配合。
- ☐ (本篇完,下一篇 3.1 列表:把多笔数据放进一个变量)