如果你刚开始学python,可能会觉得比较运算符就是简单的 > 、 < 、 == ,看一眼就会。但当你真正开始写代码,尤其是处理复杂条件判断、数据过滤或者自定义对象时,会发现事情远没这么简单。为什么两个看起来一样的字符串比较结果是 false ?为什么 1 == true 成立,而 1 is true 不成立?为什么在列表比较时, [1, 2] < [2, 1] 的结果是 true ?这些看似“基础”的问题,恰恰是新手写出隐蔽bug的根源。
这篇文章要解决的,就是帮你彻底理清python比较运算符和比较表达式的“潜规则”和实战要点。我们不止于罗列语法,而是要深入到python解释器如何进行比较、不同类型对象比较时的隐式转换、以及如何为你自定义的类定义比较行为。你会发现,掌握好比较运算,是写出健壮、高效条件逻辑和排序算法的基石。
读完本文,你将能清晰地回答:在什么情况下应该用 == ,什么情况下必须用 is ?如何避免浮点数比较的经典陷阱?如何让你自己写的 student 或 product 类支持 > 、 < 、 sorted() 排序?这些知识将直接提升你的代码质量和调试效率。
1. 为什么“简单”的比较运算符值得你花时间深究?
很多教程把比较运算符当作“看一眼就会”的内容,一笔带过。这导致大量python初学者在实战中踩坑。比较运算的复杂性,主要隐藏在三个层面:
第一层:值比较与身份比较的混淆。 == 检查值是否相等, is 检查是否是内存中的同一个对象。对于小整数、短字符串,由于python的驻留机制, a is b 可能碰巧为 true ,但这绝不能作为通用的相等性判断依据。误用 is 来比较值,是新手常犯的错误,且在某些情况下极难排查。
第二层:类型转换与比较规则的“隐式约定”。 当你写 10 > 9.5 时,python会自动将整数 10 转换为浮点数 10.0 再比较。但当你尝试比较一个字符串和一个数字(如 "10" > 9 )时,python 3会直接抛出 typeerror ,而在python 2中却可能产生非直观的结果。理解这些跨类型比较的规则,是避免运行时异常的关键。
第三层:自定义对象的比较行为。 当你定义了一个 person 类,默认情况下 person1 > person2 这样的操作是非法的。你必须通过实现特殊方法(如 __eq__ , __lt__ )来定义类的排序逻辑。这不仅关系到比较运算符本身,更直接影响到 sorted() 、 list.sort() 、 heapq 等内置函数能否对你的对象正常工作。
因此,深入理解比较运算符,绝非死记硬背几个符号。它关系到你代码的条件分支是否正确、数据筛选是否精准、排序功能是否如愿工作。下面,我们就从最核心的概念和原理开始拆解。
2. 核心概念:比较运算符、表达式与求值过程
2.1 比较运算符有哪些?
python提供了8个比较运算符,用于对两个值进行比较,并返回一个布尔值( true 或 false )。
| 运算符 | 名称 | 描述 | 示例(结果为 true ) |
|---|---|---|---|
== | 等于 | 检查两个操作数的值是否相等 | 5 == 5 |
!= | 不等于 | 检查两个操作数的值是否不相等 | 5 != 3 |
> | 大于 | 检查左操作数是否大于右操作数 | 10 > 7 |
< | 小于 | 检查左操作数是否小于右操作数 | 3 < 5 |
>= | 大于等于 | 检查左操作数是否大于或等于右操作数 | 7 >= 7 , 8 >= 7 |
<= | 小于等于 | 检查左操作数是否小于或等于右操作数 | 5 <= 5 , 4 <= 5 |
is | 是同一对象 | 检查两个操作数是否引用自同一个对象(内存地址相同) | a = []; b = a; a is b |
is not | 不是同一对象 | 检查两个操作数是否引用自不同对象 | a = []; b = []; a is not b |
关键区分: == vs is 这是第一个必须厘清的概念。
==是 值相等(value equality) 比较。它关心的是两个对象所代表的“内容”或“数据”是否相同。is是 身份同一(identity) 比较。它关心的是两个变量名是否指向内存中的 同一个对象 。
# 示例:列表的 == 和 is list1 = [1, 2, 3] list2 = [1, 2, 3] # 内容相同,但是一个新的对象 list3 = list1 # list3 和 list1 指向同一个列表对象 print(list1 == list2) # true,因为内容相同 print(list1 is list2) # false,因为不是同一个对象 print(list1 is list3) # true,因为指向同一个对象
一个经典的陷阱:与 none 比较 在python中, none 是一个单例对象(只有一个 none )。因此,检查一个变量是否为 none 时, 必须使用 is 或 is not ,这是公认的最佳实践。
# 正确做法
if x is none:
# do something
if x is not none:
# do something else
# 不推荐的做法(尽管有时可行,但可能引发问题)
if x == none: # 不推荐
pass为什么?因为 == 可以被类的 __eq__ 方法重载。如果一个类错误地实现了 __eq__ ,使得其实例 == none 返回 true ,就会导致逻辑错误。而 is none 基于对象身份,绝对可靠。
2.2 比较表达式与链式比较
单个比较运算(如 a > b )产生一个布尔值。但python允许你将多个比较运算 链式(chaining) 连接在一起,形成更简洁的逻辑表达。
链式比较的格式与求值规则 a op1 b op2 c 等价于 (a op1 b) and (b op2 c) ,并且 b 只被求值一次。
x = 5 # 链式比较:检查 x 是否在 1 到 10 之间(包含) print(1 <= x <= 10) # true # 等价于 print((1 <= x) and (x <= 10)) # true # 更复杂的链式比较 y = 7 print(0 < x < y < 10) # true,等价于 0 < x and x < y and y < 10
链式比较不仅让代码更简洁、更接近数学表达,而且在某些情况下能借助短路求值( and )带来微小的性能优势和安全保障(中间表达式 b 只计算一次)。
2.3 比较表达式的求值过程
当你写下 a == b 时,python解释器内部发生了什么?
- 获取操作数 :计算
a和b的值。 - 类型检查与转换 :如果两个操作数类型不同,python会尝试寻找一个共同的比较基础。对于数字类型(int, float, complex),python会进行隐式转换。对于其他不兼容的类型(如str和int),在python 3中会引发
typeerror。 - 调用特殊方法 :这是核心。对于
a == b,python会尝试调用a.__eq__(b)。如果a的类没有实现__eq__方法,python会尝试调用b.__eq__(a)(但顺序和结果处理有特定规则)。如果都没有实现,默认使用对象身份比较(即is)。 - 返回结果 :将特殊方法返回的值转换为布尔值。通常
__eq__应返回true或false,但也可以返回其他值,python会将其解释为布尔值(非空、非零即为true)。
理解这个过程,是掌握自定义类比较行为和调试比较问题的关键。
3. 环境准备:你需要一个能运行python的环境
本文的所有示例和代码均基于 python 3.8+ 环境。python 2与python 3在比较运算(特别是字符串与数字比较)上有重大差异,现代开发已全面转向python 3。
基础环境检查: 打开你的终端(windows cmd/powershell, macos/linux terminal)并输入:
python --version # 或 python3 --version
确认输出为 python 3.x.x 。
推荐工具:
- 交互式环境 :使用python自带的idle,或更强大的
ipython、jupyter notebook,可以方便地逐行测试比较表达式。 - 代码编辑器/ide :vs code、pycharm等,它们能提供语法高亮和即时错误提示。
- 在线环境 :如果你暂时没有本地环境,可以使用 python官方在线shell 或 replit、google colab 等平台进行练习。
关键配置提醒: 确保你的ide或编辑器使用的是正确的python解释器。在vs code中,可以通过点击左下角状态栏的python版本号进行切换。在pycharm中,需要在项目设置中配置解释器。
4. 各类数据类型的比较行为详解
不同类型的数据,比较的规则大相径庭。理解这些规则是避免错误的前提。
4.1 数字类型(int, float, complex)的比较
数字类型的比较最符合直觉,支持混合类型比较(隐式转换)。
# 整数与浮点数 print(5 == 5.0) # true,整数5被转换为浮点数5.0 print(10 > 9.5) # true print(3.14 <= 3) # false # 复数(complex)比较 # 注意:复数仅支持 `==` 和 `!=`,不支持大小比较(`>`, `<`, `>=`, `<=`) c1 = 3 + 4j c2 = 3 + 4j c3 = 1 + 2j print(c1 == c2) # true print(c1 != c3) # true # print(c1 > c2) # 这会引发 typeerror: '>' not supported between instances of 'complex' and 'complex'
浮点数比较的经典陷阱 由于浮点数在计算机中是以二进制近似表示的,直接使用 == 比较两个计算得到的浮点数可能不可靠。
# 不可靠的比较
result = 0.1 + 0.2
print(result == 0.3) # false!输出可能是 false
print(result) # 0.30000000000000004
# 可靠的比较方法:使用容差(epsilon)
def is_close(a, b, rel_tol=1e-9, abs_tol=0.0):
return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
print(is_close(0.1 + 0.2, 0.3)) # true
# python 3.5+ 提供了官方解决方案:math.isclose
import math
print(math.isclose(0.1 + 0.2, 0.3)) # true4.2 序列类型(str, list, tuple)的比较
序列类型的比较是 字典序(lexicographical order) 比较:逐个元素进行比较,直到分出大小或其中一个序列耗尽。
# 字符串比较(按字符的unicode码点)
print('apple' < 'banana') # true,因为 'a' < 'b'
print('cat' > 'car') # true,第三个字符 't' (116) > 'r' (114)
print('10' < '2') # true!注意:这是字符串比较,'1'(49) < '2'(50)
# 列表比较
print([1, 2, 3] < [1, 2, 4]) # true,第三个元素 3 < 4
print([1, 2] < [1, 2, -1]) # true,第一个列表是第二个列表的前缀
print([1, 2, 3] == [1, 2, 3]) # true,元素完全相同
print([1, 2] > [2, 1]) # false,第一个元素 1 < 2
# 元组比较(规则同列表)
print((1, 'a') < (2, 'b')) # true重要提醒 :要比较两个序列是否完全相等(长度相同且每个对应元素相等),必须使用 == ,而不是 is 。
4.3 其他内置类型的比较
- 字典(dict) :在python 3中,字典仅支持
==和!=,比较的是键值对是否完全一致。不支持大小比较(>,<)。d1 = {'a': 1, 'b': 2} d2 = {'b': 2, 'a': 1} d3 = {'a': 1} print(d1 == d2) # true,顺序不影响相等性 print(d1 != d3) # true # print(d1 > d2) # typeerror: '>' not supported between instances of 'dict' and 'dict' - 集合(set) :同样只支持
==和!=,比较的是元素是否相同。此外,集合还支持子集、超集比较运算符(<,<=,>,>=),这些运算符被重载用于集合关系判断,而非元素大小。s1 = {1, 2, 3} s2 = {3, 2, 1} s3 = {1, 2} print(s1 == s2) # true print(s1 != s3) # true print(s3 < s1) # true,s3是s1的真子集 print(s1 >= s3) # true,s1是s3的超集
4.4 跨类型比较的规则与陷阱
在python 3中, 大多数不相关的内置类型之间不支持比较 ,会直接抛出 typeerror 。这是一个重要的改进,避免了python 2中许多令人困惑的行为。
# python 3 中的行为 # print(10 > '5') # typeerror: '>' not supported between instances of 'int' and 'str' # print([1, 2] > (1, 2)) # typeerror: '>' not supported between instances of 'list' and 'tuple'
唯一的例外是数字类型(int, float, complex)之间可以比较,以及前面提到的集合的子集比较。
5. 实现自定义类的比较功能
默认情况下,自定义类的实例仅支持 == 和 != ,并且 == 的比较基于对象身份( is ),这通常不符合我们的需求。为了让你的类支持完整的比较操作( < , > , <= , >= ),你需要实现相应的特殊方法。
5.1 基础实现:__eq__和__lt__
假设我们有一个 student 类,我们想根据学生的成绩进行比较。
class student:
def __init__(self, name, score):
self.name = name
self.score = score
# 实现等于
def __eq__(self, other):
if not isinstance(other, student):
return notimplemented # 告诉python尝试调用other的__eq__
return self.score == other.score
# 实现小于
def __lt__(self, other):
if not isinstance(other, student):
return notimplemented
return self.score < other.score
# 测试
s1 = student("alice", 85)
s2 = student("bob", 92)
s3 = student("charlie", 85)
print(s1 == s3) # true,因为分数相同
print(s1 == 85) # false,因为85不是student实例,__eq__返回notimplemented,最终回退到身份比较
print(s1 < s2) # true,85 < 92
print(s2 > s1) # true!注意:我们没有实现__gt__,但python能根据__lt__自动推导出s2 > s1关键点解析:
isinstance(other, student):这是一个类型检查。确保我们只与同类的其他实例进行比较。如果other不是student,我们返回notimplemented。这是一个特殊的单例值,告诉python“我不知道怎么比较,你去问问other有没有办法”。这保证了比较操作的对称性尝试。return notimplemented:这是实现二元运算符特殊方法时的最佳实践。它允许python尝试交换操作数顺序再次调用比较方法(例如,如果a.__eq__(b)返回notimplemented,python会尝试b.__eq__(a))。- 自动生成的反向操作 :当你只定义了
__lt__(小于)后,python会自动将__gt__(大于)理解为other.__lt__(self)。同理,__le__(小于等于)和__ge__(大于等于)也可以通过__lt__和__eq__组合推导出来。但为了清晰和性能,有时需要显式定义。
5.2 完整实现与functools.total_ordering装饰器
为了支持所有比较运算符,理论上你需要实现 __eq__ , __lt__ , __le__ , __gt__ , __ge__ 。但python的 functools 模块提供了一个装饰器 @total_ordering ,可以大大简化这个工作:你只需要定义 __eq__ 和 一个 大小比较方法(如 __lt__ ),它就能自动帮你补全其他方法。
from functools import total_ordering
@total_ordering
class student:
def __init__(self, name, score):
self.name = name
self.score = score
def __eq__(self, other):
if not isinstance(other, student):
return notimplemented
return self.score == other.score
def __lt__(self, other):
if not isinstance(other, student):
return notimplemented
return self.score < other.score
# 可选:为了更好的字符串表示
def __repr__(self):
return f"student(name='{self.name}', score={self.score})"
# 现在student类支持所有比较运算符
s1 = student("alice", 85)
s2 = student("bob", 92)
s3 = student("charlie", 85)
print(s1 <= s3) # true (s1 == s3)
print(s1 < s2) # true
print(s2 >= s1) # true
print(s1 != s2) # true (s1.__eq__(s2)为false,所以!=为true)使用 @total_ordering 的注意事项:
- 它确实方便,但会稍微增加一点函数调用的开销,因为缺失的方法是通过组合已有的
__eq__和__lt__动态生成的。 - 对于性能极其敏感的场合,或者类非常简单时,手动实现所有方法可能更直接。
- 确保你定义的
__eq__和__lt__逻辑是 一致 的,否则自动生成的方法可能产生违反直觉的结果(例如,a == b为true,但a <= b为false)。
5.3 让自定义对象支持排序
实现了比较运算符的类,其对象可以直接用于 sorted() 函数或列表的 sort() 方法。
students = [
student("david", 78),
student("eve", 95),
student("frank", 85),
student("grace", 92)
]
# 按分数升序排序
sorted_students = sorted(students)
print(sorted_students)
# 输出: [student(name='david', score=78), student(name='frank', score=85), student(name='grace', score=92), student(name='eve', score=95)]
# 降序排序
sorted_students_desc = sorted(students, reverse=true)
print(sorted_students_desc)
# 输出: [student(name='eve', score=95), student(name='grace', score=92), student(name='frank', score=85), student(name='david', score=78)]
# 使用列表的sort方法原地排序
students.sort(key=lambda s: s.score) # 也可以直接用students.sort(),因为我们定义了__lt__
print(students)key 参数与比较方法的关系 : sorted() 和 list.sort() 的 key 参数接受一个函数,该函数用于从每个元素中提取一个用于比较的键。即使你的类没有实现比较运算符,也可以通过 key 参数进行排序。但实现了比较运算符后,排序逻辑更内聚,使用起来也更直观。
6. 实战:构建一个支持复杂比较的产品类
让我们通过一个更复杂的例子,巩固对自定义比较的理解。假设我们有一个 product 类,包含名称、价格和库存。我们想定义这样的排序规则: 首先按价格升序,价格相同则按库存降序(库存多的优先) 。
from functools import total_ordering
from dataclasses import dataclass
# 使用dataclass简化属性定义,它自动生成__init__和__repr__等方法
@dataclass
@total_ordering
class product:
name: str
price: float
stock: int
# 定义相等:名称、价格、库存都相同才是同一个商品(这里假设名称唯一)
def __eq__(self, other):
if not isinstance(other, product):
return notimplemented
# 在实际业务中,可能有一个唯一id,这里用名称简化
return (self.name, self.price, self.stock) == (other.name, other.price, other.stock)
# 定义小于:先比较价格,价格相同则比较库存(库存多的“更小”,因为我们要降序)
def __lt__(self, other):
if not isinstance(other, product):
return notimplemented
# 价格是第一排序键
if self.price != other.price:
return self.price < other.price
# 价格相同,库存是第二排序键(降序,所以库存多的“更小”)
return self.stock > other.stock # 注意这里的不等号方向
# 创建产品列表
products = [
product("laptop", 999.99, 10),
product("mouse", 25.50, 100),
product("keyboard", 89.99, 25),
product("tablet", 299.99, 5),
product("cheap mouse", 25.50, 150), # 与mouse价格相同,库存更多
]
print("原始列表:")
for p in products:
print(f" {p}")
print("\n按规则排序后(价格升序,价格相同则库存降序):")
sorted_products = sorted(products)
for p in sorted_products:
print(f" {p}")运行结果分析:
原始列表: product(name='laptop', price=999.99, stock=10) product(name='mouse', price=25.5, stock=100) product(name='keyboard', price=89.99, stock=25) product(name='tablet', price=299.99, stock=5) product(name='cheap mouse', price=25.5, stock=150) 按规则排序后(价格升序,价格相同则库存降序): product(name='cheap mouse', price=25.5, stock=150) # 价格最低,且在同价中库存最高 product(name='mouse', price=25.5, stock=100) # 价格最低,库存次高 product(name='keyboard', price=89.99, stock=25) product(name='tablet', price=299.99, stock=5) product(name='laptop', price=999.99, stock=10)
可以看到, cheap mouse 和 mouse 价格相同(25.5),但 cheap mouse 库存更多(150 > 100),因此在排序中它排在前面,符合我们“库存降序”的次级规则。这个例子清晰地展示了如何通过 __lt__ 实现多级、混合方向的复杂排序逻辑。
7. 常见问题与排查思路
在python比较运算中,你可能会遇到以下典型问题。下表列出了现象、可能原因和解决方案。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
typeerror: '>' not supported between instances of 'x' and 'y' | 1. 尝试比较两个不支持比较的类型(如int和str)。 2. 自定义类未实现比较运算符,或实现有误(如未返回 notimplemented )。 | 1. 检查操作数的类型。 2. 对于自定义类,检查 __lt__ , __gt__ 等方法是否正确定义,并在遇到不支持的类型时返回 notimplemented 。 | 1. 确保比较的操作数类型兼容。对于数字和字符串比较,先进行显式类型转换(如 int('5') )。2. 完善自定义类的比较方法。 |
浮点数比较结果不符合数学预期(如 0.1+0.2 == 0.3 为false) | 浮点数的二进制表示存在精度误差。 | 打印出浮点数的实际值(如 print(0.1+0.2) )。 | 使用 math.isclose(a, b) 或自定义容差函数进行比较,绝对不要直接用 == 比较计算得到的浮点数。 |
两个“看起来一样”的列表或字典, == 比较返回 false | 1. 内容确实有细微差别(如尾随空格、不可见字符、不同的数据类型)。 2. 嵌套结构中包含浮点数。 3. 顺序问题(对于字典,python 3.7+保证插入顺序,但 == 不关心顺序)。 | 1. 使用 repr() 打印,查看精确表示。2. 逐元素比较,或使用 pprint 模块格式化输出。3. 对于字典,检查键值对是否完全一致。 | 1. 清洗数据,确保类型一致。 2. 对于嵌套的浮点数,考虑深度比较并使用 math.isclose 。3. 使用 difflib 模块辅助查找差异。 |
| 自定义类对象排序结果混乱或报错 | 1. 未实现比较运算符( __lt__ 等)。2. 实现的比较运算符逻辑不一致(如 __eq__ 和 __lt__ 冲突)。3. 使用了 @total_ordering 但基础方法( __eq__ , __lt__ )实现有误。 | 1. 检查类是否定义了 __lt__ 或使用了 @total_ordering 。2. 编写单元测试,验证比较关系(如 a<b , b>a , a==b )是否自洽。 | 1. 正确定义 __eq__ 和至少一个排序方法( __lt__ )。2. 使用 @total_ordering 简化实现,并确保基础方法逻辑正确且一致。 |
is 判断结果与预期不符(如对小整数、短字符串) | 误用了 is 进行值比较。python对小整数(-5到256)和短字符串有驻留优化,但这只是实现细节,不可依赖。 | 思考你的意图:是比较值还是检查是否为同一个对象? | 永远使用 == 进行值相等比较 。 is 仅用于与 none 、 true 、 false 等单例的比较。 |
链式比较 a < b < c 的结果不符合 (a<b) and (b<c) | 几乎不可能,这是语言定义的行为。如果出现,极可能是 b 在两次比较中值发生了变化(如 b 是函数调用或具有副作用的表达式)。 | 检查中间表达式 b 是否是幂等的(多次求值结果相同)。 | 确保链式比较中的表达式没有副作用。如果 b 的计算成本高或有副作用,应将其赋值给一个变量后再进行链式比较。 |
8. 最佳实践与工程建议
将比较运算的知识应用到实际项目中,需要遵循一些最佳实践,以确保代码的正确性、可读性和可维护性。
与 none 比较,一律使用 is 和 is not 这是python社区的黄金法则。它绝对可靠,且意图清晰。
浮点数比较,永远不要直接用 == 或 != 对于任何涉及浮点数的相等性判断,使用 math.isclose() 。对于大小比较,如果计算结果可能包含微小误差,考虑使用容差。
# 错误
if calculated_value == expected_value:
pass
# 正确
import math
if math.isclose(calculated_value, expected_value, rel_tol=1e-9):
pass为自定义类实现比较运算符时,总是返回 notimplemented 在你的 __eq__ 、 __lt__ 等方法中,如果遇到不支持的类型,务必返回 notimplemented ,而不是抛出 typeerror 或返回 false 。这允许python尝试交换操作数进行比较,保持了运算符的预期行为。
优先使用 @total_ordering 装饰器 除非有极致的性能要求,否则使用 functools.total_ordering 可以让你只定义 __eq__ 和一个排序方法(如 __lt__ ),代码更简洁,且不易出错。
确保比较关系的一致性 如果你手动实现了多个比较运算符,必须确保它们逻辑一致。例如,必须满足:如果 a == b 为真,则 a <= b 和 a >= b 也必须为真。使用 @total_ordering 可以自动保证这种一致性。
在 sorted 或 sort 中, key 参数通常比定义 __lt__ 更灵活 如果排序逻辑只是临时性的,或者有多种排序方式,使用 sorted(list, key=lambda x: x.attr) 比修改类的 __lt__ 更合适。 key 函数直接返回用于比较的键,清晰且无副作用。
理解比较运算符的短路行为在链式比较中的应用 a < b < c 中,如果 a < b 已经是 false ,则 b < c 不会再被求值。这可以用来安全地编写边界检查,例如 if 0 <= index < len(array): ,即使 index 是负数,也不会触发 len(array) 的越界比较错误(因为第一部分已是false)。
小心可变对象在比较和集合中的使用 如果一个对象是可变的(如列表、字典),并且你基于其内容定义了 __eq__ 和 __hash__ (使其可放入集合或作为字典键),那么一旦对象被修改,它在集合或字典中的位置就会错乱,导致无法找到。通常,只有不可变对象才适合作为字典的键或集合的元素。
掌握python的比较运算符,远不止记住 > 、 < 、 == 这几个符号。它涉及对python对象模型、类型系统、运算符重载和排序算法的深入理解。从最基础的数值、字符串比较,到自定义类的复杂排序逻辑,比较运算贯穿了python编程的方方面面。通过本文的梳理,希望你能清晰地辨别 == 与 is 的应用场景,能优雅地处理浮点数比较的陷阱,并能为你定义的任何数据模型赋予灵活而准确的比较能力。下次当你需要实现一个排序功能,或是编写一个条件判断时,不妨回想一下这些规则和最佳实践,它们能帮你写出更健壮、更地道的python代码。
到此这篇关于python比较运算符之从基础概念到自定义类排序实战的文章就介绍到这了,更多相关python比较运算符内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论