Python 系列(七) 类型转换详解,int()、float()、str() 与金额计算避坑
1 | 作者:李晓辉 |
- Python 系列(一) 从零开始认识 Python,入门其实没那么难
- Python 系列(二) 学 Python 的第一步,把开发环境搭建好
- Python 系列(三) 基础语法避坑指南,缩进、大小写、续行与注释
- Python 系列(四) Python 输入输出详解,print()、input() 与常见避坑指南
- Python 系列(五) 数值类型与运算符详解,整除、浮点精度与进制转换实战
- Python 系列(六) 字符串处理实战,查找、替换、切片与日志分析
- Python 系列(七) 类型转换详解,int()、float()、str() 与金额计算避坑
- Python 系列(八) Python 流程控制入门,掌握 if、elif 和 else
- Python 系列(九) Python 逻辑运算符详解,and、or、not 一篇搞懂
- Python 系列(十) while、for 循环实战,彻底搞懂 range、break 与 continue
为什么 int("98.76") 会报错,而 int(98.76) 却可以?为什么 input() 拿到的数字必须先转换成 int 才能相加?为什么金额计算时,不能简单地使用 float 计算,再用 str() 转成字符串输出?
这些问题看起来很基础,却是 Python 初学者经常遇到的坑。在处理用户输入、读取配置文件、分析日志以及编写 Linux 运维脚本时,类型转换几乎无处不在。
上一篇我们学习了字符串的创建、常用方法和切片操作。现在,程序已经能够处理文本了,接下来就要解决一个重要问题:如何将字符串转换成数字,又如何将数字转换成字符串?
这篇文章将从基础规则讲起,结合实际代码和运维场景,把 Python 的数值与字符串类型转换讲清楚。
为什么需要类型转换?
先看一个简单的例子。
1 | a = input("请输入第一个整数:") |
运行程序,输入两个数字:
1 | 请输入第一个整数:10 |
咦?输入的是 10 和 20,为什么结果不是 30,而是 1020?
原因就在于 input() 的返回值。
input() 始终返回字符串。 即使用户输入的是数字,Python 也不会自动将它转换成整数。
可以通过 type() 查看变量的类型:
1 | a = input("请输入一个数字:") |
输入 10 后,输出如下:
1 | 请输入一个数字:10 |
这里的 10 实际上是字符串 "10",不是整数 10。
对于字符串,+ 运算符表示拼接,因此:
1 | print("10" + "20") |
输出:
1 | 1020 |
如果需要进行数学运算,就必须先将字符串转换为数值。
1 | a = int(input("请输入第一个整数:")) |
运行结果:
1 | 请输入第一个整数:10 |
这就是类型转换最常见的应用场景。
需要注意的是,Python 是强类型、动态类型语言。强类型意味着不同类型的数据不会在所有运算中自动进行隐式转换;动态类型则意味着变量不需要提前声明固定的数据类型。
例如,整数和浮点数可以直接相加:
1 | print(3 + 2.5) |
输出:
1 | 5.5 |
但是整数和字符串不能直接相加:
1 | print(3 + "2") |
会抛出 TypeError。
1 | Traceback (most recent call last): |
因此,编写程序时,不仅要关注变量的值,还要关注变量的类型。
Python 常用类型转换函数
先认识一下常用的转换函数。
| 函数 | 作用 | 示例 |
|---|---|---|
int() | 转换为整数 | int("123") |
float() | 转换为浮点数 | float("12.5") |
str() | 转换为字符串 | str(123) |
bool() | 转换为布尔值 | bool(1) |
chr() | 将整数码点转换为字符 | chr(65) |
ord() | 获取单个字符的 Unicode 码点 | ord("A") |
bin() | 将整数转换为二进制字符串 | bin(10) |
oct() | 将整数转换为八进制字符串 | oct(10) |
hex() | 将整数转换为十六进制字符串 | hex(255) |
这些函数中,int()、float()、str() 等既可以用于类型转换,也可以看作对应类型的构造器。
接下来逐一学习它们的用法和注意事项。
字符串转换为整数
使用 int() 转换整数
如果字符串表示一个合法的整数,就可以使用 int() 转换。
1 | number = int("123") |
输出:
1 | 123 |
转换之后,变量 number 的类型就变成了 int,可以参与整数运算。
这在运维脚本中非常常见。例如,从用户输入中读取服务器数量、端口号或重试次数,都可能需要将字符串转换为整数。
1 | server_count = int(input("请输入服务器数量:")) |
不过,这段代码有一个前提:用户必须输入合法的整数。如果输入 abc 或 12.5,转换就会失败。
为什么 int(“98.76”) 会报错?
看下面两段代码:
1 | print(int(98.76)) |
第一行输出:
1 | 98 |
第二行则会抛出:
1 | Traceback (most recent call last): |
为什么会有这样的区别?
因为 int() 对不同类型的参数采用不同的转换规则。
int(98.76):参数本身是浮点数,转换时会舍弃小数部分。int("98.76"):参数是字符串,而"98.76"并不是合法的整数形式,因此转换失败。
如果确实需要把带小数的字符串转换为整数,可以先转换为浮点数,再转换为整数:
1 | number = int(float("98.76")) |
输出:
1 | 98 |
但这里有一个容易忽略的细节:浮点数转整数是向零截断,不是四舍五入。
1 | print(int(98.76)) |
输出:
1 | 98 |
如果需要四舍五入,可以考虑 round(),但要注意 Python 对恰好位于两个整数中间的数采用“舍入到偶数”的规则。
1 | print(round(98.6)) |
输出:
1 | 99 |
所以,int()、round() 和直接转换字符串是三种不同的操作,不要混淆。
字符串转换为浮点数
如果输入的数据包含小数,可以使用 float()。
1 | price = float("19.9") |
输出:
1 | 19.9 |
float() 可以处理整数形式的字符串,也可以处理带小数点的字符串。
1 | print(float("100")) |
输出:
1 | 100.0 |
它还可以处理科学计数法:
1 | print(float("1.5e3")) |
输出:
1 | 1500.0 |
在 Linux 运维场景中,读取 CPU 使用率、内存使用率、响应时间等数据时,经常需要将文本转换为数值,以便进一步计算。
例如:
1 | cpu_usage = float("78.5") |
但是,float() 也不是万能的。
1 | float("hello") |
会抛出 ValueError,因为 "hello" 不是合法的浮点数表示。
1 | Traceback (most recent call last): |
另外,浮点数在计算机内部通常使用二进制浮点格式表示,并不是所有十进制小数都能被精确表示。金额计算时尤其需要注意这一点,后面会专门介绍。
指定进制转换为整数
除了十进制,计算机中还经常使用二进制、八进制和十六进制。
Python 的 int() 可以通过第二个参数指定输入字符串的进制。
1 | print(int("101", 2)) |
输出:
1 | 5 |
这四个结果为什么不同?
因为同样的字符 "101",在不同进制下代表不同的数值:
- 二进制
101:(1 \times 2^2 + 0 \times 2^1 + 1 \times 2^0 = 5) - 八进制
101:(1 \times 8^2 + 0 \times 8^1 + 1 \times 8^0 = 65) - 十进制
101:数值就是 101。 - 十六进制
101:(1 \times 16^2 + 0 \times 16^1 + 1 \times 16^0 = 257)
如果输入的字符串不符合指定进制的规则,就会转换失败。
1 | print(int("123", 2)) |
运行后会抛出 ValueError,因为二进制只能使用 0 和 1,不能出现 2 或 3。
1 | Traceback (most recent call last): |
在 Linux 运维中,这种转换可以用于分析十六进制掩码、处理协议字段,或者解析以特定进制保存的配置值。
例如:
1 | hex_string = "ff" |
输出:
1 | 255 |
这里的 "ff" 是十六进制字符串,转换成整数后才可以正常参与数学运算。
数字转换为字符串
使用 str() 转换
当需要将数字与文本拼接、生成日志或输出格式化内容时,可以使用 str()。
1 | number = 123 |
输出:
1 | 123 |
需要注意的是,str() 只是将对象转换为字符串表示,并不会改变原对象本身的类型。
1 | number = 123 |
输出:
1 | <class 'int'> |
变量 number 仍然是整数,变量 text 才是字符串。
实际开发中,如果只是输出内容,通常不需要手动调用 str()。print() 可以接收多个参数,而 f-string 可以更方便地将数值嵌入文本中。
1 | server_count = 20 |
这两种写法都可以输出服务器数量。
将整数转换为二进制、八进制和十六进制字符串
Python 提供了三个常用函数:
1 | number = 255 |
输出:
1 | 0b11111111 |
注意,这三个函数返回的都是字符串。
它们的前缀分别表示:
0b:二进制。0o:八进制。0x:十六进制。
如果不希望显示前缀,可以使用格式化语法:
1 | number = 255 |
输出:
1 | 11111111 |
其中,x 输出小写十六进制字母,X 输出大写字母。
这种方式在日志输出、调试位掩码以及查看二进制数据时很有用。
字符与整数之间的转换
Python 还提供了 ord() 和 chr(),用于字符与 Unicode 码点之间的转换。
1 | print(ord("A")) |
输出:
1 | 65 |
ord() 用于获取单个字符的 Unicode 码点,chr() 则将合法的 Unicode 码点转换为对应字符。
再看一个例子:
1 | print(ord("中")) |
输出:
1 | 20013 |
需要注意,ord() 接收的是长度为 1 的字符串,而不是任意长度的字符串。
1 | print(ord("AB")) |
这会抛出 TypeError。
1 | Traceback (most recent call last): |
另外,ord() 获取的是 Unicode 码点,并不等于字符在 UTF-8 编码中的字节值。处理字符编码时,需要区分字符、码点和字节这几个概念。
转换失败怎么办?使用异常处理
前面已经多次看到,类型转换并不总是成功。
例如:
1 | int("hello") |
会抛出 ValueError。
1 | Traceback (most recent call last): |
如果程序没有处理这个异常,运行就可能中断。因此,在读取用户输入、配置文件或外部接口数据时,应该考虑转换失败的情况。
使用 try-except 捕获异常
1 | try: |
当用户输入合法整数时,程序正常执行;如果输入 abc、18.5 或空字符串,就会进入 except 分支,提示用户重新检查输入。
这里捕获的是 ValueError,因为这些输入的问题在于无法按照整数规则完成转换。
不过,这段代码只会提示错误,不会自动要求用户再次输入。如果希望用户一直输入,直到获得合法结果,可以使用循环。
循环校验,直到输入合法
下面模拟一个简单的工号输入场景:工号必须是正整数。
1 | while True: |
这里有几个值得注意的地方:
input()先获取字符串。int(raw)尝试将字符串转换为整数。emp_id <= 0用于检查业务规则。- 如果输入不合法,就通过
raise ValueError主动抛出异常。 break只有在输入通过校验后才会执行。
要特别注意,能够成功转换,不代表输入一定符合业务要求。
例如,int("-10") 可以成功,但如果工号必须为正数,仍然应该拒绝这个值。
在生产脚本中,除了数据类型,还要校验取值范围、必填条件和业务规则。
金额计算为什么不建议直接使用 float?
来看一个常见的购物场景。
1 | price = float(input("请输入商品价格:")) |
输入价格 19.9,购买数量 3,结果可能是:
1 | 请输入商品价格:19.9 |
为什么不是 59.7?
这是因为 float 通常采用 IEEE 754 二进制浮点数表示。像 19.9 这样的十进制小数,无法被二进制浮点格式精确表示,因此计算结果可能出现微小误差。
这并不意味着 float 不好用。它非常适合许多数值计算,例如测量数据、科学计算和性能指标分析。
但对于金额这类需要严格控制十进制精度的业务,通常更适合使用 decimal.Decimal。
使用 Decimal 进行金额计算
1 | from decimal import Decimal |
输入:
1 | 请输入商品价格:19.9 |
输出:
1 | 总价:59.70 |
这里有两个关键点。
第一,使用 Decimal 处理金额时,应该优先从字符串构造:
1 | from decimal import Decimal |
输出:
1 | 0.3 |
不要先将十进制小数转换成 float,再传给 Decimal:
1 | from decimal import Decimal |
输出:
1 | 0.1000000000000000055511151231257827021181583404541015625 |
这种写法会保留浮点数 0.1 的实际二进制近似值,因此得到的结果可能包含许多额外的小数位。
第二,{total:.2f} 表示以两位小数的格式输出。这主要是输出格式控制,并不意味着所有业务计算都已经自动完成了金额舍入。
如果业务要求每一步都按特定规则舍入,例如按照分进行结算,就需要明确规定舍入时机和舍入方式,并使用 Decimal.quantize() 等方法实现。
记住:金额计算不仅要考虑数据类型,还要考虑精度、舍入规则和业务要求。
类型转换在 Linux 运维中的应用
类型转换不仅是入门语法,也是编写自动化运维脚本的基础。
假设你从配置文件或命令输出中获取了 CPU 使用率:
1 | cpu_usage = "78.5" |
由于 cpu_usage 是字符串,必须先转换为浮点数,才能与数值 80 进行比较。
再看一个内存容量计算的例子:
1 | memory_total = "16384" |
输出:
1 | 内存使用率:75.00% |
这个例子中,两个变量最初都是字符串。转换成整数后,程序才能执行除法和乘法计算。
不过,真实的 Linux 命令输出通常包含单位、表头或其他文本。例如,free -h 会输出带有 Gi、Mi 等单位的容量,不能简单地对整行文本调用 int()。实际编写脚本时,还需要先解析出目标字段,再根据单位转换数值。
同样,从日志中提取的响应时间、从 API 返回的数值字段,以及从环境变量读取的端口号,都需要根据实际数据格式进行类型转换和校验。
可以用下面的流程理解整个过程:
flowchart TD
A["用户输入 / 配置文件 / 日志"] --> B["获取原始字符串"]
B --> C{"需要数值运算吗?"}
C -->|否| D["保留字符串"]
C -->|是| E["使用 int() / float() / Decimal()"]
E --> F{"转换成功吗?"}
F -->|是| G["检查业务规则和取值范围"]
F -->|否| H["捕获异常并提示或记录错误"]
G --> I{"校验通过吗?"}
I -->|是| J["执行计算"]
I -->|否| H
J --> K["格式化输出或写入日志"]这个流程不仅适用于 Python 初学练习,也适用于实际的运维自动化程序。
综合练习:安全的数值输入与输出
最后,写一个综合示例,将前面学到的知识串起来。
要求:
- 提示用户输入一个整数。
- 将输入转换为整数,并计算加 10 的结果。
- 输出二进制、八进制和十六进制表示。
- 捕获非法输入,避免程序直接中断。
参考代码:
1 | try: |
输入:
1 | 请输入一个整数:255 |
输出:
1 | 原值 + 10 = 265 |
如果输入 hello,程序不会直接因为 ValueError 而终止,而是输出:
1 | 输入无效,请输入合法整数。 |
你可以继续尝试输入 -10、0、12.5 和空字符串,观察不同输入的处理结果。
写在最后
这一篇我们学习了 Python 数值与字符串之间的转换规则。
需要重点掌握的内容有:
input()始终返回字符串,数学运算前要根据需要转换类型。int()可以转换合法整数形式的字符串,也可以将浮点数向零截断为整数;int("98.76")则会报错。float()可以转换合法的浮点数字符串,但要注意二进制浮点数的精度问题。str()可以将数值转换为字符串,但不会改变原变量的类型。int(x, base)可以将指定进制的字符串转换为整数,bin()、oct()和hex()可以将整数转换为相应进制的字符串。ord()和chr()用于 Unicode 字符与码点之间的转换。- 使用
try-except处理非法输入,并进一步检查业务规则和取值范围。 - 金额计算优先考虑
Decimal,从字符串构造,并明确舍入规则。
类型转换看起来只是几行代码,却决定了程序能否正确处理真实数据。 尤其是在 Linux 运维自动化中,用户输入、命令输出、配置文件和 API 数据往往都是以文本形式进入程序。先理解数据类型,再进行转换、校验和计算,才能写出更加可靠的 Python 脚本。
