Python技术迷

python面试题:python内建数据类型有哪些?

讲真,要说起 Python 的内建数据类型,很多新手第一反应就是死记硬背:int、bool、str、list、tuple、dict……然后期末考试过了,转头就忘。但你真当了几年 Python 工程师,写的代码从“能跑就行”到“能维护不炸”,你会发现——这些基础类型,它们不只是考试用的名词,它们是你写出优雅代码的地基,是你调试半天发现“哦原来是类型不对”的那块绊脚石。

今天我们就不搞死板罗列,我来聊聊这几个内建类型在开发中的“真实身份”,以及它们那些容易被忽视的小陷阱。

int:别以为只有整数这么简单

Python 的整型(int)本质上是无限精度的。也就是说,你可以写出一个有几千位的整数,它都能正常处理,比如:

x = 10 ** 100
print(x)

这在 C 或 Java 中根本不可能——你早就 overflow 到外太空去了。但 Python 不怕,它就是慢点。

不过慢也不是白慢的,底层其实是做了不少处理,把 int 存成一个变长对象,所以它大了是真的大,但你也别用来搞那种精密度超高的科学计算,精度可以,速度会气死你。

讲个坑,int(True) 是 1,int(False) 是 0,这是因为布尔类型其实是整型的子类:

print(isinstance(True, int))  # 输出 True

所以你如果写了一堆 dict 的键是 1 和 True,那祝你好运,可能直接覆盖了。

bool:逻辑判断的搅屎棍

看似简单的布尔类型,坑也不少。Python 判断“真值”并不只看 True 和 False,很多你以为“有内容”的对象其实是 False,比如:

bool([])  # False
bool('')  # False
bool(0)   # False

但别以为你能全靠 if not xxx: 来判断对象是否存在,尤其是在写 Web 接口时,比如某个字段为空字符串 "",你就以为用户没填,这就可能搞出数据污染,尤其是和数据库字段联动时。

还有一种骚操作是,True + True 的结果是 2,因为 True 是 int 啊。这事我同事在写单元测试断言的时候翻车了:

assertTrue + True == True# 这行不会报错,但永远是 False

str:Unicode 是个麻烦精

字符串在 Python 3 里是 Unicode,这点非常棒,终于不用再在文件开头写 # -*- coding: utf-8 -*- 那一堆了。但同时,也让处理字节流和文本变得复杂了——尤其是你要处理爬虫返回的 HTML、或者跟外部系统对接数据流。

比如:

s = '你好'
b = s.encode('utf-8')
print(b)  # 输出 b'\xe4\xbd\xa0\xe5\xa5\xbd'
print(b.decode('utf-8'))  # 又变回来了

看起来很爽对吧?但你只要一个 .decode('ascii') 打错,就崩了。而且有些编码(比如 gbk)跟 utf-8 是不兼容的,报错不报错完全看你传入的数据里有没有“中文”。

别的不说,光是字符串的拼接就够让人折寿了。新手最爱用 +,老鸟都用 .join(),为什么?因为性能啊朋友!

# 慢
s = ''
for i in range(10000):
    s += str(i)

# 快
s = ''.join(str(i) for i in range(10000))

你要是写日志还用 + 拼接,几万个字符串下来 CPU 都得哭。

list:看似万能,实则危险

列表是最常用的数据结构之一,但也是最容易被滥用的。比如新手喜欢写:

list1 = [[0]*3]*3
list1[0][0] = 1
print(list1)

你以为是创建了 3 个不互相影响的行,实际是 3 个引用指向同一个列表,结果整行全变了。这种错,我当年进公司第一天就写出来了,导师只回了俩字:“经典”。

正确方式应该是:

list1 = [[0for _ in range(3)] for _ in range(3)]

此外,列表是可变对象,传参的时候一不小心就变成了“副作用制造机”:

defappend_one(lst=[]):
    lst.append(1)
return lst

print(append_one())  # [1]
print(append_one())  # [1, 1],你以为是新列表,其实是同一个默认值

这个陷阱可以说毁人不倦,解决方法也很简单,把默认值设为 None,然后在函数体内判断。

tuple:真的不可变吗?

元组(tuple)被很多人当成“不可变的 list”,但这里有个误区:元组本身不可变,但元组里面的元素可以是可变的。

t = ([1, 2], 3)
t[0][0] = 99
print(t)  # ([99, 2], 3)

看到没?你不能 t[0] = ...,但你可以 t[0][0] = ...,这就很魔性。

这也是为什么元组能做字典的 key,但前提是它“里面的东西也不能变”,不然你就拿不到 key 了。

dict:键值对是个学问

字典是 Python 里最强大的数据结构之一,但也是最容易出问题的,比如 dict 的键必须是“可哈希”的(hashable),你不能用 list 做 key:

d = {[1, 2]: 'hello'}  # 报错

还有一个坑是,字典的遍历在 Python 3.6+ 虽然“看起来有顺序”,但你别指望它真的保证顺序,除非你用 OrderedDict,或者升级到 Python 3.7+ 后再说“字典是有序的”。

我朋友在写一个数据缓存系统的时候,写死了遍历顺序,换个环境直接翻车……因为他用了 Python 3.5。

还有一点,字典合并不是 +,而是 update(),或者 Python 3.9 开始支持的 | 运算符:

a = {'x': 1}
b = {'y': 2}
c = a | b  # Python 3.9+

别乱用老的合并方式,比如手动遍历赋值,这样不仅慢,而且容易漏掉 key 冲突的处理逻辑。

所以说,Python 的内建类型看似简单,其实个个暗藏玄机。你要真想写好 Python,光靠记名字是远远不够的,得理解它们背后的数据模型、内存行为,还有跟实际开发的互动。

别再背什么“int 是整型,list 是列表”了,那都是小学生水平。

作为一个 Python 工程师,你的任务是搞清楚这些类型怎么在代码里“坑你”,然后“帮你”。

写得清楚,不出 bug,那才是硬实力。

不然你写的不是 Python,是炸弹。

最后,我为大家打造了一份deepseek的入门到精通教程,完全免费:https://www.songshuhezi.com/deepseek

也可以看我写的这篇文章《DeepSeek满血复活,直接起飞!》来进行本地搭建。

对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
🔥虎哥私藏精品 热门推荐🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》。

资料包含了《IDEA视频教程》、《最全python面试题库》、《最全项目实战源码及视频》及《毕业设计系统源码》,总量高达650GB,全部免费领取。