写在之前
大家好,我是 MuSen,一个爱分享、带你轻松玩转编程的引路人。无论你是刚接触代码的小白,还是正在准备大厂面试、想要夯实基础的同学,来到这里就对了。
在上一节中,我们聊了“变量”这个贴标签的魔法盒子。今天,我们要深入盒子的内部,看看里面装的到底是什么“货”——也就是 Python 中的数据类型。
这一篇,我不仅会教你“怎么用”,更会带你扒开 Python 的源代码,看看底层的“为什么”。这篇文章里融合了无数初学者容易踩坑的细节,并且埋藏了大量大厂面试的高频考点(比如小整数池、Intern机制、深浅拷贝、浮点数精度等)。
知识点很多,但我保证,只要跟着我的节奏,那些看似高深的名词都会变得像喝水一样简单。准备好了吗?我们发车!🚀
1.1 数据类型:盒子里到底装了啥?
在 Python 的世界里有一句至理名言:“变量无类型,数据才有类型。” 变量 a 只是一个随时可以换地方贴的标签,而真正分门别类的是内存中的数据对象。Python 里的数据主要分为以下六大门派:
数值(Number):整数(int)、浮点数(float)、复数(complex)、布尔(bool)
字符串(String):比如
"Hello MuSen"列表(List):用
[]装起来的一排数据(今天的新朋友!)元组(Tuple):用
()装起来的不可变数据集合(Set):用
{}装起来的去重神器字典(Dictionary):带有键值对的
{key: value}特殊类型(None):表示“四大皆空”、啥也没有。
💡 MuSen 的面试必考科普:可变与不可变 面试官常问:“Python 中哪些是可变类型,哪些是不可变类型?为什么?”
不可变数据(铁公鸡,改不了):数值、字符串、元组。修改它们的值,本质上是重新在内存中开辟了一块新空间,然后把变量标签贴过去,原地址的数据不能变。正因为不可变,它们才能作为字典的 Key(可哈希)。
可变数据(橡皮泥,随便捏):列表、字典、集合。你可以在原有的内存地址上直接修改里面的内容(比如追加元素),内存地址
id()不会变。
1.2 数值家族:整型、浮点型与布尔值
1.2.1 整型 (int) 与四则运算的魔法 🧮
Python 处理整数的能力极其彪悍!与其他编程语言(如 C/Java 需要区分 int, long, short)不同,Python 的整型只有一种,它可以处理任意大小的整数,包括负整数。 不管你输入的数字多大,只要你电脑的内存管够,它就算飞到了天际也跑不出 Python 的五指山,永远不会出现溢出(Overflow)的问题。
除了熟悉的 +、-、*,Python 里的进阶运算大有学问:
/(普通除法):无论能不能除尽,结果永远是浮点数!哪怕是4 / 2,结果也是2.0。//(整除/向下取整):注意,它是向下取整!10 // 3是3;但-10 // 3结果是-4(面试坑点⚠️)。%(取模/余数):5 % 2结果是1。(指数):算次方的神器。
2 3结果是8。
🧠 面试超硬核专区:小整数池与大整数池 面试官:“解释一下
a = 256; b = 256; print(a is b)和a = 257; b = 257; print(a is b)的结果?” MuSen 答疑: 为了提升性能,避免频繁申请和销毁内存空间,Python 解释器在启动时偷偷建了一个小整数池(范围是 [-5, 256])。在这个范围内的整数都是提前在内存中造好的,全局共享。 所以如果是256,a is b为 True。如果是257,超出了范围,底层会为 a 和 b 分别开辟新的内存,所以a is b为 False! (注:在 PyCharm 等 IDE 中运行由于编译器的常量折叠优化,257 也可能返回 True,但原生的命令行交互环境必定是 False!答出这个细节,面试官直接给你疯狂加分!)
1.2.2 浮点型 (float):带着小数点的刺客 🎯
所有带小数点的数都是浮点数。同样,Python 也不区分单精度和双精度,统统都是 float。
⚠️ 致命陷阱:精度丢失(经典面试题) 面试官:“为什么 0.1 + 0.2 == 0.3 在 Python 中是 False?” MuSen 答疑:不仅是 Python,几乎所有语言都会这样!因为计算机底层是用二进制的 IEEE 754 标准来存储浮点数的。0.1 和 0.2 转换成二进制是一个无限循环小数,计算机会进行截断,导致最终相加的结果是 0.30000000000000004。
🦸♂️ 拯救方案:如果涉及金融、交易的精准计算,请请出 decimal 模块!
from decimal import Decimal
f1 = Decimal("0.1")
f2 = Decimal("0.2")
print(f1 + f2 == Decimal("0.3")) # 输出: True (完美解决!)
1.2.3 布尔型 (bool):非黑即白的裁判 ⚖️
布尔值只有两个:True (真) 和 False (假)。它是 int 的小弟(在底层,bool 是 int 的子类),所以可以参与数学计算:
print(True == 1) # True
print(True + True) # 输出 2!惊不惊喜?
除了 False,Python 中还有这些天生为假 (Falsy) 的家伙:None, 0, 0.0, 以及所有的空容器("", [], (), {})。在写 if 判断时,直接写 if not 列表: 判空是最优雅的写法。
1.3 字符串 (str):所见即所得的魔术 📝
字符串是由零个或多个字符组成的序列,用单引号 ''、双引号 "" 或三引号 """ """ 括起来。
1.3.1 字符串的神奇算术:拼接与复制
相加(拼接):
'Hello' + ' ' + 'World'结果是'Hello World'。相乘(复制):字符串还能做乘法?没错!
'Python' * 3会直接输出'PythonPythonPython',极其方便!
1.3.2 逃脱大师:转义字符与 r 原生字符串
如果你的字符串里有单引号:'what\'s your name',直接写会报错。需要用反斜杠 \ 转义,或者外层用双引号 "what's your name"。 常见的转义字符有:\n(换行)、\t(Tab)、\r(回车)。
如果你不想让 \ 发生转义(比如写正则或 Windows 路径),在字符串前加个 r,它就会变成原生字符串:
print(r'c:\now') # 输出 c:\now,原汁原味,不把 \n 识别成换行!
1.3.3 切片大师:把字符串大卸八块 🔪
字符串里的每一个字符都有索引(编号)。
正向索引:从
0开始。反向索引:从
-1开始。
切片 (Slicing) 公式:[起始:结束:步长]。左闭右开(包含左边,不包含右边)!
string = 'I love Python'
print(string[2:6]) # 输出: 'love'
print(string[7:]) # 输出: 'Python' (一直截取到末尾)
print(string[::-1]) # 经典面试题:一行代码反转字符串!输出: 'nohtyP evol I'
提示:切片对原字符串没有任何影响,它是切出了一个全新的字符串。
1.3.4 必备的字符串方法 (Methods)
Python 给你准备了各种现成的字符串工具,可以通过 dir(str) 查看,千万别自己造轮子!
.find('ov'):查找子串,找到返回开始的索引,找不到返回-1。.index('l'):跟 find 一样,但如果找不到,它会直接报错(抛出 ValueError)。.count('i'):统计某个字符在字符串中出现的次数。.replace('旧', '新', 次数):把指定的子串替换成新的,可以指定替换几次。.split(','):根据指定的字符把字符串“劈开”,返回一个列表。.strip():一键洗澡,去掉字符串左右两边的所有空白字符(包括空格、换行等)。
1.3.5 字符串格式化(必学 F-string)
传统的 %s 和 .format() 已经老了,现在是 f-string 的天下(Python 3.6+):
name = "MuSen"
age = 18
print(f"大家好,我是 {name},今年 {age} 岁!") # 极其优雅,且运行速度最快!
🧠 面试超硬核专区:字符串的 Intern 机制 (驻留机制) 面试官:“什么是字符串驻留?” MuSen 答疑:Python 为了节省内存,对于只包含字母、数字、下划线的字符串(且在编译期就能确定的),默认开启 Intern 机制,相同的字符串在内存中只保留一份,靠引用计数决定是否销毁!
a = "hello_world" b = "hello_world" print(a is b) # True
1.4 字符编码的前世今生:情报局加密通信 🕵️♀️
要讲编码,得讲个故事。长官下令冲锋,小兵吹冲锋号(这就是编码);士兵听见号声,大脑明白要冲锋(这就是解码)。 计算机底层只认识 0 和 1 的高低电平。你要让它懂“你好中国”,就得有一套“密码本”,这就叫字符编码。
1.4.1 编码史诗三部曲
ASCII 码:60年代美国人发明的密码本,128个字符,1个字节。只够存英文。
Unicode 码(万国码):像秦始皇统一度量衡,把世界上绝大多数文字都编排进了一套标准里。但在内存中统一占用2个或4个字节,存英文太浪费空间了!
UTF-8:互联网的救星。它是 Unicode 的一种实现方式,可变长度编码。存英文只用1个字节,存汉字用3个字节,既兼容又省内存。
1.4.2 字符对应的密码:ord() 与 chr()
因为 Python3 支持 Unicode,每个字都有一个对应的“身份证号”(编码数字):
ord('中'):查看字符对应的数字编码(结果:20013)。chr(20013):通过数字编码找回对应的字符(结果:'中')。
1.4.3 Python3 中的 Encode 与 Decode
在 Python3 中,所有在内存中活蹦乱跳的字符串都是 Unicode! 只有当你需要保存到硬盘或通过网络发送时,才需要将其转换为机器能懂的二进制 bytes 类型。
str1 = "你好中国"
# 1. 编码 (Encode):人话(str) -> 机器话(bytes)。默认用 utf-8
byte1 = str1.encode(encoding='utf-8')
print(byte1) # 输出: b'\xe4\xbd\xa0...' (可以看到,UTF-8里一个汉字变成了3个十六进制字节)
# 2. 解码 (Decode):机器话(bytes) -> 人话(str)。
str2 = byte1.decode(encoding='utf-8')
💣 面试踩坑警告:用什么密码本加密,就得用什么密码本解密!如果用 UTF-8 编码却用 GBK 解码,就会出现满屏的“锟斤拷”乱码。
1.5 列表 (List):海纳百川的魔法背包 🎒
如果一个变量只能装一个数据,那太憋屈了。在 Python 中,用方括号 [] 表示的 列表(List) 就是你的神奇背包! 里面可以装数字、字符串,甚至是其他列表。列表里元素的个数理论上是无限大的,只看你电脑的硬件脸色行事。
1.5.1 列表的基本使用与专属方法
列表也是序列,完美继承了字符串的“切片”和“索引”能力,并且它支持倒着数(-1 代表最后一个)。 除了常见的 append(),这里介绍两个极其好用的内置方法:
.extend(可迭代对象):合并大师!从另一个列表里获取元素,把它们全部追加到自己的尾巴上,达到扩充的目的。.index(元素):真正的查岗神器。查询某个元素在列表中第一次出现的位置索引。
my_list = [10, 20]
my_list.extend([30, 40]) # 把新列表合并进来
print(my_list) # 输出: [10, 20, 30, 40]
print(my_list.index(30)) # 输出: 2
🧠 面试超硬核专区:列表的时间复杂度 (Big O) 面试官:“在列表头部插入元素和尾部追加元素,哪个快?” MuSen 答疑:尾部快!Python 的列表底层是一个动态数组(一块连续的内存空间)。
append()(尾部追加):不需要移动其他元素,时间复杂度是 O(1)。
insert(0, value)(头部插入):为了给新元素腾位置,后面所有的元素都要集体往后挪一步!时间复杂度是 O(N),数据量大时极其卡顿!
1.5.2 绝杀面试:浅拷贝与深拷贝
这是 Python 面试必考的重点!只要涉及嵌套列表,坑就来了。
import copy
old_list = [1, 2, [3, 4]]
# 1. 赋值 (=):不是拷贝!相当于给同一个箱子多贴了个标签。两人共享一切。
# 2. 浅拷贝 (copy()):只拷贝第一层!
shallow = old_list.copy()
shallow[2][0] = 999
print(old_list) # 输出: [1, 2, [999, 4]]。原列表的内层也被改了!因为浅拷贝只拷贝了内层列表的引用地址。
# 3. 深拷贝 (deepcopy()):彻彻底底的拷贝,连内层嵌套的列表也重新在内存里挖了一块新空间。
deep = copy.deepcopy(old_list)
deep[2][0] = 888
print(old_list) # 原列表毫发无损!两人彻底分家。
1.6 变身大作战:数据类型转换 🔄
最后,不同数据类型之间是可以换脸的!
1. 隐式转换(自动挡) 当整数遇到浮点数,Python 会自动把“格局”放大,防止数据丢失: type(2 + 3.0) 结果是 <class 'float'>。
2. 显式转换(手动挡) 你可以用函数强制转换类型:
int("456")-> 转成整数456float("12.34")-> 转成浮点数12.34str(123)-> 转成字符串"123"
💣 面试踩坑警告:警惕
eval()eval()可以脱去字符串的外衣,直接执行里面的 Python 表达式。eval("1 + 1")输出 2。 面试官:“开发中推荐用eval解析用户输入吗?” MuSen 答疑:绝对不要!如果黑客输入恶意代码如eval("os.system('rm -rf /')"),你的服务器就直接被清空删库跑路了!这是一个巨大的安全漏洞。
写在最后
今天我们深挖了各种数据类型的底牌,从小整数池、浮点数精度、字符串的内置方法,一路讲到了字符编码的前世今生、列表的底层效率以及深浅拷贝。
这些不仅是让你写代码不出 Bug 的护身符,更是你日后面试大厂、和面试官谈笑风生的核心资本。干货确实多,但我希望你不要死记硬背!打开你的 IDE 或终端,把代码敲进去跑一跑,真理都在键盘上。
我是 MuSen,我们会点儿技术,有点儿意思,这里是最懂你的地方,咱们下期见!👋