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高级架构师资料合集》。