Python快速入门专业版(十八):Python比较运算符深度解析:从基础判断到对象身份识别(附避坑指南)
目录
- 引言:比较运算符——逻辑控制的“决策核心"
- 常用比较运算符:6种基础关系与多类型适配
- 1.1 基础类型比较:数值、字符串与复数
- (1)数值类型比较(int/float)
- (2)字符串比较(str)
- (3)复数比较(complex)
- 1.2 容器类型比较:列表、元组、字典与集合
- (1)有序容器:列表(list)与元组(tuple)
- (2)无序容器:字典(dict)与集合(set)
- 1.3 特殊比较:链式比较与不同类型对比
- (1)链式比较:简化多条件判断
- (2)不同类型比较:多数情况不支持
- 2.核心避坑:`==`与`is`的本质区别(90%新手会错)
- 2.1 用`id()`函数可视化内存地址
- 2.2 `__eq__()`方法:决定`==`的判断逻辑
- 代码示例:自定义对象的`__eq__`重写
- 2.3 `==`与`is`的使用场景对比(附错误示例)
- 典型错误场景解析:
- 3.常见误区与避坑指南
- 3.1 误区1:用`is`判断容器值是否相等
- 3.2 误区2:忽视浮点数比较的精度问题
- 3.3 误区3:认为“空容器 == None”
- 3.4 误区4:链式比较中混用`and`/`or`
- 4.实战案例:比较运算符的实际应用
- 案例1:用户登录验证(多条件比较)
- 案例2:数据清洗(筛选符合条件的字典)
- 案例3:自定义对象排序(基于比较的排序)
- 总结:比较运算符的“三看”原则
引言:比较运算符——逻辑控制的“决策核心"
在Python编程中,几乎所有逻辑分支(if
语句)、循环控制(while
循环)、数据筛选(列表推导式)都依赖"关系判断"这一基础操作。而实现这一功能的核心工具就是比较运算符。它不仅能判断简单的数值关系(如"10是否大于5")、字符串是否相等这类基础比较,还能处理更复杂的场景,比如判断两个列表的值是否完全一致、变量是否为None等特殊值。
比较运算符作为Python中最基础的逻辑判断工具,其重要性体现在:
- 流程控制基础:每个
if
语句都至少包含一个比较运算 - 数据筛选核心:在列表推导式如
[x for x in lst if x > 0]
中起过滤作用 - 对象比较依据:决定自定义类实例如何判断相等性
但新手程序员常陷入两类典型误区:
-
概念混淆:分不清"值相等"(
==
)与"对象相同"(is
)的本质区别。例如:a = [1,2,3] b = a # b和a指向同一个对象 c = [1,2,3] # 新建一个值相同但内存地址不同的列表 print(a == b) # True print(a is b) # True print(a == c) # True(值相同) print(a is c) # False(不同对象)
这种混淆可能导致程序出现隐性bug,特别是在判断None值时,应该总是使用
is None
而非== None
。 -
类型忽视:不了解不同数据类型(如复数、集合、自定义类)的特殊比较规则。例如:
print({1,2} == {2,1}) # True(集合无序比较) print(1+2j == 2j+1) # True(复数实部虚部分别比较)
本文将从三个层次系统讲解比较运算符:
- 基础用法:详解6种比较运算符(
==
,!=
,>
,<
,>=
,<=
)的标准行为 - 底层原理:剖析
==
与is
的本质差异,解释Python的对象标识模型 - 实战避坑:通过10+典型代码案例,覆盖数值、字符串、容器、自定义对象等场景
特别地,我们将重点分析以下关键问题:
- 为什么
x is None
比x == None
更专业? - 如何为自定义类实现有意义的
==
比较? - 浮点数比较时的精度陷阱及解决方案
- 容器比较时的递归检查机制
通过掌握这些"判断逻辑"的底层原理,你将能够编写出更健壮、更符合Python风格的代码。
常用比较运算符:6种基础关系与多类型适配
Python提供了6种基本的比较运算符,用于比较两个值之间的关系。这些运算符返回布尔值(True
或False
),但在不同数据类型上的比较行为存在显著差异。理解这些差异对于编写正确的Python代码至关重要。
1.1 基础类型比较:数值、字符串与复数
(1)数值类型比较(int/float)
数值比较是编程中最常见的操作之一,Python支持整数和浮点数之间的比较,且会自动进行类型转换。数值比较遵循数学上的大小关系,值得注意的是浮点数比较存在精度问题。
# 1. 同类型数值比较
print("10 == 10:", 10 == 10) # True(int与int相等)
print("3.14 > 3.1415:", 3.14 > 3.1415)# False(float精度对比)
print("25 >= 25:", 25 >= 25) # True(等于满足"大于等于")
print("-5 <= -3:", -5 <= -3) # True(负数比较:绝对值大的更小)# 2. 跨类型数值比较(int与float)
print("10 == 10.0:", 10 == 10.0) # True(值相等,类型不同不影响)
print("5 > 5.0:", 5 > 5.0) # False(值相等,无大小差异)
print("9.9 < 10:", 9.9 < 10) # True(float与int混合比较)# 3. 浮点数比较的"精度陷阱"(高频坑点)
print("0.1 + 0.2 == 0.3:", 0.1 + 0.2 == 0.3) # False(浮点数存储误差)
# 解决方案:用"差值绝对值小于极小值"判断
print("abs(0.1+0.2 - 0.3) < 1e-9:", abs(0.1+0.2 - 0.3) < 1e-9) # True
关键注意:
- 浮点数比较时建议使用math.isclose()函数或差值比较法
- 跨类型比较时Python会自动进行类型转换
(2)字符串比较(str)
字符串比较遵循字典序(lexicographical order),基于字符的Unicode码点值进行比较。比较过程是从左到右逐个字符对比,直到找到差异或比较完所有字符。
# 1. 基本字符比较
print("'a' < 'b':", 'a' < 'b') # True(ASCII码97 < 98)
print("'A' < 'a':", 'A' < 'a') # True(大写字母ASCII码更小)
print("'1' < '9':", '1' < '9') # True(数字字符按顺序排列)# 2. 多字符比较
print("'apple' < 'banana':", 'apple' < 'banana') # True(首字符比较)
print("'app' < 'apple':", 'app' < 'apple') # True(前缀相同,长度短的更小)# 3. 特殊字符比较
print("' ' < 'a':", ' ' < 'a') # True(空格ASCII码32 < 97)
print("'中' > '国':", '中' > '国') # True(中文字符按Unicode码点比较)# 4. 大小写敏感比较
print("'Python' == 'python':", 'Python' == 'python') # False
实用技巧:
- 字符串比较前可先统一大小写:s.lower()或s.upper()
- 排序时可以使用sorted()函数配合key参数实现复杂排序
(3)复数比较(complex)
复数比较有其特殊性,Python只支持相等性比较,不支持大小比较。这是因为复数在数学上没有自然的排序方式。
# 1. 复数相等性比较
c1 = 3 + 4j
c2 = 3.0 + 4.0j
print(c1 == c2) # True(实部和虚部分别相等)# 2. 复数不等比较
c3 = 4 + 3j
print(c1 != c3) # True# 3. 尝试大小比较会报错
try:print(c1 > c3) # TypeError
except TypeError as e:print(f"错误:{e}")# 4. 特殊情况:虚部为0的复数
real_num = 5
c4 = 5 + 0j
print(real_num == c4) # True(实部相等,虚部为0)
注意事项:
- 复数比较时实部和虚部都必须相等
- 复数与实数比较时,虚部必须为0
- 如需比较复数大小,可比较模:abs(c1) > abs(c2)
1.2 容器类型比较:列表、元组、字典与集合
容器类型(list
/tuple
/dict
/set
)仅支持==
和!=
(判断“值是否完全一致”),不支持>
/<
等大小比较;且不同容器类型(如list
与tuple
)即使元素相同,==
也返回False
。
(1)有序容器:列表(list)与元组(tuple)
需满足“元素数量、顺序、值完全一致”,且类型相同,==
才返回True
。
# 列表比较
list1 = [1, 2, [3, 4]]
list2 = [1, 2, [3, 4]]
list3 = [1, 2, [4, 3]] # 嵌套列表顺序不同
list4 = (1, 2, [3, 4]) # 类型不同(tuple)print("list1 == list2:", list1 == list2) # True(数量、顺序、值均一致)
print("list1 == list3:", list1 == list3) # False(嵌套列表顺序不同)
print("list1 == list4:", list1 == list4) # False(类型不同)# 元组比较(规则与列表一致)
tuple1 = (10, "hello", (5, 6))
tuple2 = (10, "hello", (5, 6))
tuple3 = (10, "Hello", (5, 6)) # 字符串大小写不同
print("tuple1 == tuple2:", tuple1 == tuple2) # True
print("tuple1 == tuple3:", tuple1 == tuple3) # False
关键细节:
- 嵌套容器(如列表中的列表)会递归比较内部元素;
- 元组与列表即使元素完全相同,因类型不同,
==
仍返回False
。
(2)无序容器:字典(dict)与集合(set)
- 字典:需“键值对完全一致”(键和值均相等),与键的顺序无关(Python 3.7+保留插入顺序,但
==
仍忽略顺序); - 集合:需“元素完全一致”(无顺序、无重复),与元素添加顺序无关。
# 字典比较(键值对一致即可,顺序无关)
dict1 = {"name": "Alice", "age": 25, "hobbies": ["reading"]}
dict2 = {"age": 25, "name": "Alice", "hobbies": ["reading"]} # 键顺序不同
dict3 = {"name": "Alice", "age": 26, "hobbies": ["reading"]} # 值不同
print("dict1 == dict2:", dict1 == dict2) # True
print("dict1 == dict3:", dict1 == dict3) # False# 集合比较(元素一致即可,顺序无关)
set1 = {1, 2, 3, 4}
set2 = {4, 3, 2, 1} # 顺序不同
set3 = {1, 2, 3} # 元素数量不同
print("set1 == set2:", set1 == set2) # True
print("set1 == set3:", set1 == set3) # False
注意:
- 字典的
==
会忽略键的顺序,但需键和值均相等(值的比较遵循对应类型规则,如列表需顺序一致); - 集合因无重复元素,
{1,1,2}
与{1,2}
相等。
1.3 特殊比较:链式比较与不同类型对比
(1)链式比较:简化多条件判断
Python支持“链式比较”,即多个比较运算符连写,等价于用and
连接多个条件,代码更简洁。
# 普通写法(用and连接,冗余)
x = 15
if x > 10 and x < 20:print("x在10~20之间")# 链式比较(更简洁,等价于上述逻辑)
if 10 < x < 20:print("x在10~20之间") # 输出相同结果# 其他链式比较示例
print("5 <= x <= 15:", 5 <= x <= 15) # True(x=15,满足两个条件)
print("x > 20 or x < 10:", x > 20 or x < 10) # False(链式不支持or,需单独写)
print("1 == 1.0 == True:", 1 == 1.0 == True) # False(等价于1==1.0 and 1.0==True,1.0≠True)
注意:链式比较仅支持“逻辑与(and)”,不支持“逻辑或(or)”;若需或逻辑,需拆分为两个条件。
(2)不同类型比较:多数情况不支持
除“int
与float
”外,不同类型(如int
与str
、list
与dict
)比较大小会直接报错;比较是否相等(==
)会返回False
(无实际业务意义,不推荐使用)。
# 1. int与str比较(大小报错,相等返回False)
print("10 == '10':", 10 == '10') # False(值的类型不同,视为不等)
try:print("10 > '10':", 10 > '10')
except TypeError as e:print("不同类型比较错误:", e) # 输出:'>' not supported between instances of 'int' and 'str'# 2. list与dict比较(相等返回False,大小报错)
print("[1,2] == {'a':1}:", [1,2] == {'a':1}) # False
try:print("[1,2] < {'a':1}:", [1,2] < {'a':1})
except TypeError as e:print("容器类型比较错误:", e) # 输出:'<' not supported between instances of 'list' and 'dict'
2.核心避坑:==
与is
的本质区别(90%新手会错)
==
和is
是最易混淆的两个“判断符号”,但它们的判断维度完全不同:
==
:比较“值是否相等”(关注“内容一致”),本质是调用对象的__eq__()
方法;is
:比较“内存地址是否相同”(关注“是否为同一个对象”),本质是判断id(a) == id(b)
。
用一句话总结:“同一个对象必然值相等,但值相等的对象不一定是同一个”。
2.1 用id()
函数可视化内存地址
id(object)
是Python内置函数,返回对象的唯一内存地址标识符(整数)。通过id()
可直观看到==
与is
的差异:
# 案例1:小整数池优化(-5~256的整数复用内存)
a = 100
b = 100
c = 257
d = 257print("a == b:", a == b) # True(值相等)
print("a is b:", a is b) # True(内存地址相同,100在小整数池内)
print("id(a):", id(a), "id(b):", id(b)) # 输出相同地址,如2898567296528print("c == d:", c == d) # True(值相等)
print("c is d:", c is d) # False(257超出小整数池,内存地址不同)
print("id(c):", id(c), "id(d):", id(d)) # 输出不同地址,如2898567550224 vs 2898567550288# 案例2:字符串驻留机制(纯字母/数字/下划线的短字符串复用内存)
s1 = "python123"
s2 = "python123"
s3 = "python 123" # 含空格,不满足驻留条件
s4 = "python 123"print("s1 == s2:", s1 == s2) # True(值相等)
print("s1 is s2:", s1 is s2) # True(短字符串驻留,地址相同)
print("s3 == s4:", s3 == s4) # True(值相等)
print("s3 is s4:", s3 is s4) # False(含空格,不驻留,地址不同)# 案例3:容器类型(即使值相同,也创建新对象)
list_a = [1, 2, 3]
list_b = [1, 2, 3]print("list_a == list_b:", list_a == list_b) # True(值相等)
print("list_a is list_b:", list_a is list_b) # False(地址不同,列表不复用)
print("id(list_a):", id(list_a), "id(list_b):", id(list_b)) # 不同地址
关键原理:
- Python为节省内存,对“小整数(-5~256)”和“纯字母/数字/下划线的短字符串”做了“缓存复用”(小整数池、字符串驻留),因此相同值的对象可能共享地址;
- 容器类型(列表、字典、集合)即使值相同,也会创建新对象(无缓存机制),地址不同;
- 自定义对象默认无缓存,需手动实现(如重写
__hash__
和__eq__
)才可能复用。
2.2 __eq__()
方法:决定==
的判断逻辑
==
的本质是调用左侧对象的__eq__()
方法(如a == b
等价于a.__eq__(b)
)。默认情况下:
- 内置类型(
int
/str
/list
等)的__eq__()
已实现“值相等”判断; - 自定义对象的
__eq__()
默认调用父类object
的方法,等价于is
(比较地址)。
代码示例:自定义对象的__eq__
重写
class Student:def __init__(self, student_id, name):self.student_id = student_id # 学号(唯一标识)self.name = name# 未重写__eq__:默认比较地址
stu1 = Student(2024001, "Alice")
stu2 = Student(2024001, "Alice")
print("未重写__eq__:stu1 == stu2 →", stu1 == stu2) # False(地址不同)
print("未重写__eq__:stu1 is stu2 →", stu1 is stu2) # False# 重写__eq__:按学号判断值相等
class StudentEq(Student):def __eq__(self, other):# 先判断other是否为当前类实例if not isinstance(other, StudentEq):return False# 按学号判断相等(忽略姓名差异)return self.student_id == other.student_id# 重写后:==比较学号,is比较地址
stu3 = StudentEq(2024001, "Alice")
stu4 = StudentEq(2024001, "Alicia") # 姓名不同,学号相同
print("重写__eq__:stu3 == stu4 →", stu3 == stu4) # True(学号相等)
print("重写__eq__:stu3 is stu4 →", stu3 is stu4) # False(地址不同)
注意:重写__eq__
时,建议同时重写__hash__
(哈希值),确保“值相等的对象哈希值相同”(否则无法正常用于集合、字典的键)。
2.3 ==
与is
的使用场景对比(附错误示例)
场景需求 | 推荐使用 | 错误示例(为什么错) | 正确示例 |
---|---|---|---|
判断值是否相等(业务核心) | == | 用is 判断列表:list_a is list_b (即使值相同,也返回False,因地址不同) | 用== 判断:list_a == list_b |
判断是否为None | is | 用== 判断:x == None (虽能运行,但不规范,None 是单例,is 更高效) | 用is 判断:x is None |
判断是否为布尔值单例 | is | 用== 判断:x == True (如1 == True 返回True,易混淆“值相等”与“身份相同”) | 用is 判断:x is True |
判断数值是否在小整数池内 | is | 用is 判断大整数:257 is 257 (超出小整数池,返回False,应改用== ) | 用== 判断大整数:257 == 257 |
典型错误场景解析:
# 错误1:用is判断用户输入的年龄是否为18(业务需比较值,却用了身份判断)
age = int(input("请输入年龄:"))
if age is 18: # 危险!若age是18.0(float),即使值相等,is也返回Falseprint("您刚成年")
else:print("您不是18岁") # 若输入18.0,会错误输出此句# 正确写法:用==判断值
if age == 18:print("您刚成年")# 错误2:用==判断函数返回是否为None(不规范,且效率低)
def get_user(user_id):return None # 未找到用户时返回Noneuser = get_user(999)
if user == None: # 虽能运行,但None是单例,is更高效(直接比较地址)print("未找到用户")# 正确写法:用is判断None
if user is None:print("未找到用户")
3.常见误区与避坑指南
3.1 误区1:用is
判断容器值是否相等
容器类型(列表、字典等)即使值完全相同,也会创建新对象(地址不同),用is
判断必然返回False,需用==
。
# 错误
list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1 is list2:print("列表相同") # 不执行
else:print("列表不同") # 错误输出(实际值相同)# 正确
if list1 == list2:print("列表值相同") # 正确执行
3.2 误区2:忽视浮点数比较的精度问题
0.1 + 0.2
因浮点数存储误差,结果为0.30000000000000004
,直接用==
判断0.1+0.2 == 0.3
会返回False。
# 错误
print(0.1 + 0.2 == 0.3) # False# 正确:用差值绝对值小于极小值
print(abs(0.1 + 0.2 - 0.3) < 1e-9) # True# 进阶:用decimal模块控制精度
from decimal import Decimal, getcontext
getcontext().prec = 20 # 设置精度为20位
print(Decimal('0.1') + Decimal('0.2') == Decimal('0.3')) # True
3.3 误区3:认为“空容器 == None”
空容器(如[]
、""
、{}
)是“有值但为空”,None
是“无值”,二者==
返回False(虽均为假值,但值不同)。
# 错误:认为空列表等于None
if [] == None:print("空列表") # 不执行# 正确:判断空容器用“隐性布尔值”或`len()`
if not []: # 空列表是假值,not [] → Trueprint("空列表") # 正确执行# 区分“空容器”与“None”
data = [] # 有值(空列表)
if data is None:print("无数据")
elif not data:print("有数据,但为空") # 正确执行
3.4 误区4:链式比较中混用and
/or
链式比较仅支持“逻辑与(and)”,若需“逻辑或(or)”,需拆分为两个独立条件。
# 错误:链式比较不支持or
x = 5
if 10 < x < 20 or 0 < x < 5: # 虽能运行,但易误解为“10<x<(20 or 0)<x<5”print("x在0~5或10~20之间")# 正确:拆分or条件,用括号明确
if (0 < x < 5) or (10 < x < 20):print("x在0~5或10~20之间") # 正确执行
4.实战案例:比较运算符的实际应用
案例1:用户登录验证(多条件比较)
def login(username, password):"""验证登录:用户名存在且密码正确"""# 模拟数据库用户(用户名小写,密码加密存储,此处简化)valid_users = {"alice": "Alice@123","bob": "Bob@456"}# 1. 判断用户名是否存在(忽略大小写)lower_user = username.lower()if lower_user not in valid_users:return False, "用户名不存在"# 2. 判断密码是否相等(精确比较,区分大小写)if password == valid_users[lower_user]:return True, f"登录成功!欢迎{username}"else:return False, "密码错误"# 测试
test_cases = [("Alice", "Alice@123"), # 正确用户名+密码("bob", "Bob@4567"), # 正确用户名+错误密码("Charlie", "123456"), # 不存在用户名
]for user, pwd in test_cases:success, msg = login(user, pwd)print(f"登录({user}/{pwd}):{msg}")
# 输出:
# 登录(Alice/Alice@123):登录成功!欢迎Alice
# 登录(bob/Bob@4567):密码错误
# 登录(Charlie/123456):用户名不存在
案例2:数据清洗(筛选符合条件的字典)
def filter_products(products, min_price=0, max_price=1000):"""筛选价格在[min_price, max_price]之间的商品"""filtered = []for product in products:# 1. 确保product是字典且含"price"键if not isinstance(product, dict) or "price" not in product:continue# 2. 确保price是数值类型price = product["price"]if not isinstance(price, (int, float)):continue# 3. 比较价格是否在区间内(链式比较)if min_price <= price <= max_price:filtered.append(product)return filtered# 测试数据
products = [{"name": "T恤", "price": 89},{"name": "运动鞋", "price": 299},{"name": "手表", "price": "1500"}, # 价格是字符串,跳过{"name": "袜子", "price": 19},{"name": "背包"}, # 无price键,跳过
]# 筛选10~200元的商品
result = filter_products(products, 10, 200)
print("符合条件的商品:")
for p in result:print(f"- {p['name']}:{p['price']}元")
# 输出:
# - T恤:89元
# - 袜子:19元
案例3:自定义对象排序(基于比较的排序)
class Book:def __init__(self, title, author, price):self.title = titleself.author = authorself.price = price# 重写__eq__:按书名和作者判断是否为同一本书def __eq__(self, other):if not isinstance(other, Book):return Falsereturn self.title == other.title and self.author == other.author# 重写__lt__(小于):用于排序(按价格升序)def __lt__(self, other):if not isinstance(other, Book):raise TypeError("无法比较Book与非Book类型")return self.price < other.price# 重写__repr__:打印对象时显示友好信息def __repr__(self):return f"Book(title='{self.title}', author='{self.author}', price={self.price})"# 创建书籍列表
books = [Book("Python编程", "张三", 59.9),Book("Java编程", "李四", 69.9),Book("Python编程", "张三", 59.9), # 与第一本是“同一本书”Book("C++编程", "王五", 49.9),
]# 1. 判断是否为同一本书(基于__eq__)
book1 = books[0]
book2 = books[2]
print("book1 == book2:", book1 == book2) # True
print("book1 is book2:", book1 is book2) # False(地址不同)# 2. 按价格排序(基于__lt__)
books_sorted = sorted(books)
print("按价格升序排序:")
for book in books_sorted:print(book)
# 输出:
# Book(title='C++编程', author='王五', price=49.9)
# Book(title='Python编程', author='张三', price=59.9)
# Book(title='Python编程', author='张三', price=59.9)
# Book(title='Java编程', author='李四', price=69.9)
总结:比较运算符的“三看”原则
掌握比较运算符的核心是建立“三看”判断逻辑,避免99%的误区:
-
看需求:比"内容"还是比"身份"
- 业务逻辑中判断"值是否一致"(如用户年龄是否为18、列表元素是否相同):用
==
;- 示例:
user_age == 18
判断数值相等,["a", "b"] == ["a", "b"]
判断列表内容相同 - 应用场景:数据校验、表单提交检查、API响应比对
- 示例:
- 底层判断"是否为同一个对象"(如是否为None、是否为布尔值单例):用
is
;- 示例:
result is None
判断空值,flag is True
判断布尔值 - 应用场景:单例模式、空值检查、缓存对象比对
- 示例:
- 业务逻辑中判断"值是否一致"(如用户年龄是否为18、列表元素是否相同):用
-
看对象:是"普通类型"还是"特殊对象"
- 普通类型(int、str、list等):
==
比内容:123 == 123
为True,"hello" == "hello"
为Trueis
比地址:a = [1,2]; b = [1,2]; a is b
为False(不同对象)
- 单例对象(None、True、False):
- 只能用
is
判断(因全程序唯一) - 错误示例:
None == None
虽然为True,但不符合PEP8规范
- 只能用
- 自定义对象:
- 未重写
__eq__
时:==
等价于is
,仅比较内存地址 - 重写
__eq__
后:可按业务逻辑定义内容相等性 - 示例:
class Person:def __init__(self, name):self.name = namedef __eq__(self, other):return self.name == other.name
- 未重写
- 普通类型(int、str、list等):
-
看场景:是否有"特殊规则"
- 浮点数处理:
- 避免直接
==
:0.1 + 0.2 == 0.3
返回False - 正确做法:
abs(a - b) < 1e-9
或使用math.isclose()
- 避免直接
- 容器类型比较:
==
要求元素数量、顺序、值完全一致- 示例:
[1, 2] == [2, 1]
为False
- 示例:
is
要求内存地址相同- 示例:
a = [1]; b = a; a is b
为True
- 示例:
- 链式比较:
- 仅支持
and
逻辑:1 < x < 10
等价于1 < x and x < 10
- 需
or
逻辑时必须拆分:x < 1 or x > 10
- 仅支持
- 特殊场景:
- 字符串驻留:小字符串
is
可能为True但不建议依赖 - 不可变对象:相同值的
is
可能为True但不保证
- 字符串驻留:小字符串
- 浮点数处理:
通过这一原则,你能精准选择合适的比较方式,写出逻辑清晰、无隐性bug的代码,让"判断"成为编程中的"确定性工具",而非"踩坑点"。实际应用时建议:
- 业务数据比较优先用
==
- 单例对象必须用
is
- 浮点比较用误差范围
- 自定义类实现
__eq__
- 避免依赖实现细节的
is
比较