
Python 里很多人第一次接触内置对象,都是从 list、dict 这些容器开始,很少有人认真看数字对象。
但线上写代码久了会发现,数字类型才是最容易被忽略的一类对象。
比如金额计算、分页数量、统计结果、时间戳处理,这些地方每天都在和数字打交道。很多线上隐藏 Bug,不是业务逻辑错了,而是数字类型理解得不够深。
Python 的数字类型不像 Java 那样有 int、long、float 一堆固定范围,也不像 C 语言那样需要时刻担心溢出。
Python 把数字也当成对象处理。
比如:
count = 100
print(type(count))
print(id(count))
输出:
<class 'int'>
140725634...
这里的 100 并不是一个简单的内存值,而是一个 int 对象。
Python 中常见的数字对象主要有:
int:整数
float:浮点数
complex:复数
bool:布尔类型(特殊的整数)
平时业务开发中,使用最多的是 int 和 float。
先聊 int。
Python3 里的 int 和很多语言不太一样。
以前写 Java 的时候,经常需要考虑:
int max = 2147483647;
long value = 999999999999L;
因为 int 有固定范围。
Python2 时代其实也有类似区别:
# Python2
a = 100
print(type(a))
小整数默认是:
<type 'int'>
如果超过 int 范围,会自动转换成 long:
num = 999999999999999999
print(type(num))
结果:
<type 'long'>
到了 Python3,这两个类型合并了。
现在:
num = 999999999999999999999999999999
print(type(num))
结果:
<class 'int'>
没有 long 了。
Python3 的 int 可以动态扩展。
不过这里有一个容易踩坑的地方。
很多人看到 Python 整数没有限制,就觉得随便算。
实际上不是没有成本。
比如:
total = 10 ** 100000
print(len(str(total)))
这个数字有十万位。
虽然 Python 能处理,但是计算、存储、转换字符串都会消耗资源。
线上如果有人把用户输入直接拿来计算:
number = int(request.args["num"])
result = number ** 10000
这种代码看起来没问题,实际上可能直接把 CPU 打满。
所以数字没有溢出,不代表没有风险。
我自己排查接口性能问题时,遇到过类似情况。
业务方传了一个统计参数,本来设计是查询月份:
202501
结果没有限制范围,被传成了几十位数字。
后面的计算逻辑没有报错,但是 CPU 使用率直接上涨。
Python 不会帮你拒绝这种数字。
边界校验还是业务自己的事情。
再说 float。
Python 的浮点数底层使用的是 IEEE 754 双精度浮点。
简单理解:
很多十进制小数,并不能被计算机精确表示。
比如:
price = 0.1 + 0.2
print(price)
结果:
0.30000000000000004
这个问题很多刚接触 Python 的同学第一次都会觉得奇怪。
0.1 加 0.2 为什么不是 0.3?
不是 Python 算错了,而是二进制无法精准表示某些十进制小数。
比如:
a = 0.1
print(format(a, ".20f"))
结果类似:
0.10000000000000000555
你看到的 0.1,其实只是显示出来进行了舍入。
所以金额计算千万不要直接使用 float。
比如:
money = 19.99
discount = money * 0.8
print(discount)
这种写法在支付、账务系统里面风险很大。
一般有两种处理方式。
第一种,使用整数保存最小单位。
比如金额单位是分:
price_fen = 1999
discount = 80
real_price = price_fen * discount // 100
print(real_price)
结果:
1599
保存整数,不参与浮点计算。
第二种,使用 Decimal。
from decimal import Decimal
price = Decimal("19.99")
rate = Decimal("0.8")
result = price * rate
print(result)
输出:
15.992
Decimal 会按照十进制规则计算。
这里有个细节。
不要这样写:
Decimal(0.1)
因为 float 本身已经不准确了。
应该:
Decimal("0.1")
字符串进入 Decimal,才能保持精度。
再看看 bool。
Python 里面 bool 其实是 int 的子类。
这个很多人不知道。
执行:
print(isinstance(True, int))
print(True + True)
结果:
True
2
因为:
True == 1
False == 0
所以:
data = [True, False, True]
print(sum(data))
结果:
2
这在统计代码里挺常见。
比如统计成功数量:
records = [
{"success": True},
{"success": False},
{"success": True},
]
success_count = sum(item["success"] for item in records)
print(success_count)
输出:
2
这种写法很简洁。
但是业务代码里别滥用。
有些地方字段类型应该明确:
status = 1
和:
success = True
表达的意思不是一回事。
数据库字段设计时尤其注意。
还有一个 Python 数字对象的小细节:对象复用。
比如:
a = 10
b = 10
print(a is b)
很多情况下:
True
因为 Python 对一些小整数进行了缓存。
但是不要依赖这个。
比如:
a = 10000
b = 10000
print(a is b)
结果可能:
False
判断数字是否相等,用:
a == b
不要:
a is b
is 判断的是是不是同一个对象。
这个坑我在代码 review 里见过几次。
开发同学想优化比较,结果把 is 当成 == 用。
小数字测试没问题,上线换数据直接出问题。
最后补一个 Python2 和 Python3 数字类型最大的区别之一:
Python2:
print(5 / 2)
结果:
2
因为两个整数相除还是整数。
Python3:
print(5 / 2)
结果:
2.5
Python3 修改了除法行为。
如果想保持整数除法:
print(5 // 2)
结果:
2
这个变化迁移老项目时非常容易踩坑。
比如 Python2 代码:
page_count = total / page_size
以前默认得到整数。
迁移 Python3 后:
page_count = 10 / 3
直接变:
3.3333333333333335
后面的分页逻辑全部乱掉。
正确写法:
page_count = (total + page_size - 1) // page_size
比如:
total = 101
page_size = 20
pages = (total + page_size - 1) // page_size
print(pages)
输出:
6
这个写法在分页接口里很常见。
数字类型看起来简单,但真正写业务时,到处都是坑。
整数精度、浮点误差、类型转换、Python2 到 Python3 的行为变化,这些东西平时不出问题,一出问题往往都是线上。
代码能跑只是第一步,知道 Python 背后怎么处理这些数字对象,才不会在一些奇怪的问题上浪费时间。
以上就是“浅谈Python内置对象类型——数字篇(附py2和py3的区别之一)!”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://www.phpxs.com/post/14658/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料