# Python有哪些内置数据类型?
面试官问:“Python有哪些内置数据类型?”
很多录友会直接报一串名字:int、float、str、list、dict……名字报全了,面试官往往还会追一句:“这些类型怎么分类?哪些可变?”这道题真正考的是分类思路。类型名只是起点,能讲清每类类型存什么、能不能原地修改、能不能作为字典键,才算答到位。
# 简要回答
Python 3常用的内置数据类型可以分成几类:数值类型int、float、complex;序列类型str、list、tuple,以及range、bytes;映射类型dict;集合类型set和frozenset;另外还有布尔类型bool和空值None。
分类之外更重要的是可变性。list、dict、set是可变对象,可以原地增删改;数值、str、tuple、frozenset、bytes是不可变对象,任何“修改”都会得到新对象。可变性直接决定了一个对象能不能作为字典的键、多个变量共享它时是否安全。
还有两个常被追问的细节:bool是int的子类,True和False在数值运算中相当于1和0;None是NoneType的唯一实例,判断时用is None。
# 详细回答
# 按“存什么、怎么存”分类

图的上半部分是按用途分类,下半部分把同样的类型按可变性重新划分。序列和集合两类同时连到两侧,说明“同一类里也有可变和不可变之分”,这正是面试时容易漏答的地方。
| 类别 | 常见类型 | 存的是什么 | 是否可变 |
|---|---|---|---|
| 数值 | int、float、complex | 整数、浮点数、复数 | 不可变 |
| 序列 | str、tuple、bytes、range | 有序元素,支持索引和切片 | 不可变 |
| 序列 | list | 有序元素,支持索引和切片 | 可变 |
| 映射 | dict | 键值对,按键查找 | 可变 |
| 集合 | set / frozenset | 不重复元素 | 可变 / 不可变 |
| 特殊值 | bool、NoneType | 真假值、空值 | 不可变 |
# 数值类型:整数不会溢出,浮点数有精度误差
int在Python 3中是任意精度的,只受内存限制,不会像C++的int那样溢出。float是双精度浮点数,按二进制存储,十进制小数常常无法精确表示:
print(2 ** 100) # 1267650600228229401496703205376
print(0.1 + 0.2) # 0.30000000000000004
2
2 ** 100得到的是精确整数;0.1 + 0.2的误差来自二进制浮点表示,不是Python的bug。需要精确十进制计算时,比如金额,可以使用标准库decimal。
# 容器类型:区别在顺序、索引方式和可变性
str、list、tuple都是序列,元素有顺序,通过整数下标访问。dict按键访问值,从Python 3.7开始,语言层面保证字典保持插入顺序。set关注的是元素是否存在和去重,不支持下标访问。
这几种容器的细节分别放在后续文章里:字符串见《Python字符串为什么不可变?》,列表和元组见《Python列表和元组有什么区别?》,字典和集合见《Python字典和集合有什么区别?》。
# bool和None:两个特殊的常客
bool是int的子类,这是Python语言层面的设计,不是CPython的实现细节:
print(issubclass(bool, int)) # True
print(True + True) # 2
2
另外,任何对象都能参与真值判断。空容器、0、""和None判断为假,非空容器判断为真,所以[0]是真值,因为列表里有一个元素。
None表示“没有值”,函数没有写return时返回的就是它。整个解释器中只有一个None对象,所以用is None判断身份,既准确又不会被自定义的__eq__干扰。
# 动态类型,但不是弱类型
Python变量本身没有类型,类型属于对象。同一个名字可以先绑定整数,再绑定字符串,这叫动态类型。但Python不会在不相关的类型之间偷偷转换:
print(int("3") + 1) # 4
print("3" + 1) # TypeError: can only concatenate str (not "int") to str
2
字符串和整数相加直接报错,必须显式转换,这说明Python是强类型语言。“变量没有类型”具体指什么,可以接着看《Python变量保存的是什么?》。
# 知识拓展
面试官可能追问:
Q1:type()和isinstance()有什么区别?
type(obj)返回对象的确切类型,isinstance(obj, cls)会把子类也算进去。比如type(True) == int是False,isinstance(True, int)是True。日常判断类型更推荐isinstance(),它能正确处理继承关系。
Q2:可变类型和不可变类型在使用上有什么差别?
不可变对象的“修改”都会创建新对象,多个变量共享它不会互相影响;可变对象可以原地修改,共享时一处改动处处可见。这背后是对象身份和名字绑定的问题,完整解释见《Python中的可变对象和不可变对象有什么区别?》。
Q3:为什么列表不能作为字典的键?
字典靠键的哈希值定位数据,键在使用期间哈希值不能变。列表可以原地修改,内容一变哈希值就失效,所以list被设计为不可哈希。需要用序列作键时,可以改用元素都可哈希的元组。
Q4:bool为什么要设计成int的子类?
Python早期用1和0表示真假,后来引入bool时,为了兼容已有代码,就让它继承int。这样sum([True, False, True])可以直接统计真值个数。不过业务代码里拿布尔值做算术,可读性并不好。
评论
验证登录状态...