值与类型:名字绑定了什么
核心概念
Python 中的一切都是对象。数字是对象,字符串是对象,函数也是对象。名字(变量)不存储对象本身,而是绑定到对象的引用。
关键区别:
- 对象:内存中的实体,有身份(identity)、类型(type)、值(value)
- 名字:指向对象的标签,可以重新绑定到不同对象
- 绑定:让名字指向对象的操作(通过
=赋值)
对象身份与 is 运算符
每个对象都有唯一的身份标识,可以用 id() 函数获取(CPython 中是内存地址):
>>> a = 1000
>>> b = 1000
>>> id(a)
140234567890123
>>> id(b)
140234567890456
>>> a is b
Falseis 运算符检查两个名字是否绑定到同一个对象(身份相同),而 == 检查值是否相等:
>>> a == b
True
>>> a is b
Falsea 和 b 的值相等(都是 1000),但它们是内存中的不同对象。
小整数缓存
Python 缓存了小整数对象(通常是 -5 到 256)以提高性能:
>>> x = 5
>>> y = 5
>>> x is y
True
>>> id(x) == id(y)
True这是 CPython 的实现细节,不应依赖它编写逻辑。判断对象身份用 is,判断值相等用 ==。
名字绑定不是赋值
许多语言中,x = 5 表示"把 5 存入变量 x"。Python 中的含义是:
- 创建或找到整数对象
5 - 让名字
x绑定到这个对象
>>> x = 42
>>> y = x
>>> x = 100
>>> print(y)
42解释:
x = 42:名字x绑定到整数对象 42y = x:名字y也绑定到同一个整数对象 42x = 100:名字x重新绑定到新对象 100y仍然绑定到原来的对象 42,不受影响
可视化:
x = 42 → [42] ← x
y = x → [42] ← x, y
x = 100 → [42] ← y [100] ← x基本类型
整数(int)
Python 3 的整数是任意精度的,不会溢出:
>>> big = 10 ** 100
>>> print(big)
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
>>> type(big)
<class 'int'>浮点数(float)
使用 IEEE 754 双精度浮点数,有精度限制:
>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False浮点数不能精确表示所有十进制小数。金融计算应使用 decimal.Decimal(后续讲解)。
字符串(str)
不可变的 Unicode 文本序列:
>>> s = "Hello"
>>> type(s)
<class 'str'>
>>> len(s)
5
>>> s[0]
'H'字符串用单引号 '...' 或双引号 "..." 包围,语义相同。多行字符串用三引号:
>>> text = """This is
... a multi-line
... string"""
>>> print(text)
This is
a multi-line
string布尔值(bool)
只有两个值:True 和 False(注意大写):
>>> is_valid = True
>>> type(is_valid)
<class 'bool'>
>>> 5 > 3
True
>>> 5 == 3
False布尔值是整数的子类:
>>> True + True
2
>>> int(True)
1
>>> int(False)
0None
表示"无值"或"空":
>>> result = None
>>> type(result)
<class 'NoneType'>
>>> result is None
TrueNone 是单例对象,整个程序中只有一个 None。检查是否为 None 应使用 is None,不用 == None。
类型检查
使用 type() 获取对象的类型:
>>> type(42)
<class 'int'>
>>> type(3.14)
<class 'float'>
>>> type("hello")
<class 'str'>使用 isinstance() 检查对象是否属于某个类型(或其子类):
>>> isinstance(42, int)
True
>>> isinstance(True, int)
True
>>> isinstance(3.14, int)
False
>>> isinstance(3.14, (int, float)) # 检查多个类型
Trueisinstance() 比 type() 更灵活,因为它支持继承。
可变 vs 不可变对象
不可变对象:创建后值不能改变。包括 int, float, str, tuple, frozenset。
>>> x = "hello"
>>> x[0] = "H" # 尝试修改字符串
TypeError: 'str' object does not support item assignment不可变对象的"修改"实际是创建新对象:
>>> s = "hello"
>>> s_id = id(s)
>>> s = s + " world"
>>> id(s) == s_id
Falses + " world" 创建了新字符串对象,s 重新绑定到新对象。
可变对象:可以原地修改。包括 list, dict, set。
>>> lst = [1, 2, 3]
>>> lst_id = id(lst)
>>> lst.append(4)
>>> lst
[1, 2, 3, 4]
>>> id(lst) == lst_id
True列表对象的身份没变,但内容变了。
多个名字绑定到可变对象
>>> a = [1, 2, 3]
>>> b = a
>>> b.append(4)
>>> print(a)
[1, 2, 3, 4]a 和 b 绑定到同一个列表对象,通过 b 修改对象会影响 a。这不是复制,而是别名(aliasing)。
要创建独立副本,使用 copy() 或切片:
>>> a = [1, 2, 3]
>>> b = a.copy() # 或 b = a[:]
>>> b.append(4)
>>> print(a)
[1, 2, 3]
>>> print(b)
[1, 2, 3, 4]动态类型
Python 是动态类型语言:名字可以重新绑定到任何类型的对象:
>>> x = 42
>>> type(x)
<class 'int'>
>>> x = "now a string"
>>> type(x)
<class 'str'>这在静态类型语言中会报错,但 Python 允许。对象有类型,名字没有类型约束(除非使用类型注解,后续章节讲解)。
练习
身份与相等:预测下列代码的输出,然后实际运行验证:
pythona = [1, 2, 3] b = [1, 2, 3] c = a print(a == b) print(a is b) print(a is c)不可变对象:解释为什么以下代码中
y没有变化:pythonx = 10 y = x x = x + 5 print(y) # 输出是什么?可变对象陷阱:运行以下代码并解释结果:
pythonlist1 = [1, 2, 3] list2 = list1 list2[0] = 999 print(list1)如何修改代码使
list1不受影响?类型检查:编写函数
check_type(obj),打印对象的类型、是否为整数、是否为数字(int 或 float):pythondef check_type(obj): # 你的代码 pass check_type(42) check_type(3.14) check_type("hello")小整数缓存边界:实验确定小整数缓存的上限(提示:从 256 开始尝试)。
完成练习后,打开本章答案页核对。
下一步
理解了对象与名字绑定,下一节学习控制流:如何用 if、while、for 让程序做出决策和重复操作。
回到第一章概览 · 返回Python 学习路线