python怎么⽐较元组的⼤⼩_Python中的元组排序和深度⽐较Python部落(python.freelycode)组织翻译,禁⽌转载,欢迎转发。
⽐较Python中的东西。这听起来⼏乎是不需要教的,但是我发现Python的⽐较运算符经常被Python新⼿误解和低估。
我们来回顾⼀下Python的⽐较运算符如何处理不同类型的对象,然后看看如何使⽤这些⽐较运算符来提⾼代码的可读性。
Python中的⽐较运算符
我这⾥所说的 “⽐较运算符”是指相等运算符(== 和!=)和排序运算符(,>=)。
我们可以⽤这些运算符来⽐较数字,正如你所期望的:
除此之外,我们也可以⽤这些运算符来⽐较字符串:
甚⾄于元组::
许多编程语⾔都没有与Python⾮常灵活的⽐较运算符等价的运算符。
稍后我们将看⼀看这些运算符如何处理元组和更复杂的对象,我们先从简单⼀点的开始:字符串⽐较。
Python中的字符串⽐较
字符串的相等和不相等⼗分简单。如果两个字符串有完全相同的字符,那么它们是相等的:
注意,我忽略了⼀个⾮常⼤的例外: unicode字符。通常有多种⽅法可以表⽰相同的⽂本,在将这些不同的表⽰视为相等之前,必须对它们进⾏标准化。为了简单起见,本⽂将坚持使⽤ASCII字符。
字符串的排序是Python中⽐较有趣的部分:
字符串“pickle”⽐字符串“python”⼩,因为我们是按字母顺序排序的…⼤⼩写有⼀部分作⽤::
字符串“Python”⼩于“pickle”,因为P⼩于p。
这⾥我们与其说是按照字母顺序还不如说是按照ASCII- 码顺序排序的 (因为我们在python3中实际是使⽤unicode-码)。这些字符串是按照它们的字符的ASCII码值排序的(ASCII码中p是112,⽽P是80)。
从技术上讲,Python是⽐较这些字符的Unicode代码点(这是ord函数所做的事情),⽽这恰好与⽐较ASCII字符的ASCII码值结果相同。
字符串的排序规则是:使⽤==操作符⽐较每个字符串的第n个字符(从第⼀个字符开始,索引为0);如果它们相等,则对下⼀个字符重复这个步骤
对于两个不相等的字符,取具有较低代码点的字符,并声明其所在字符串“⼩于”另⼀个
如果所有字符都相等,那么字符串也是相等的
如果⼀个字符串在步骤1中耗尽字符(⼀个字符串是另⼀个字符串的“前缀”),则较短的字符串“⼩于”较长的字符串
Python⽤于⽐较字符串的排序算法可能看起来很复杂,但它与字典中使⽤的排序算法⾮常相似;不是Python中的字典,⽽是物理字典(我们在互联⽹出现之前使⽤的那些东西)。当在字典中对单词排序时,我们优先考虑第⼀个字符,如果⼀个单词是另⼀个单词的前缀,那么它就会排在前⾯。
元组的⽐较
我们可以问元组是否相等,就像我们可以问字符串是否相等⼀样:
但是我们也可以使⽤排序运算符(,>=)来⽐较元组:
字符串排序可能有些直观(我们⼤多数⼈在Python之前就已经学习了字母排序),但是元组排序⼀开始并不那么直观。但实际上你已经对元组排序有点熟悉了,因为元组排序和字符串排序使⽤相同的算法。
元组排序的规则(本质上与字符串排序相同):
使⽤==运算符⽐较每个元组的第n项(从第⼀个项开始,索引为0);如果它们相等,则对下⼀项重复这个步骤
对于两个不相等的项,“⼩于”的项使包含它的元组也“⼩于”另⼀个元组
如果所有项都相等,则元组相等
如果⼀个元组在步骤1中耗尽了项(⼀个元组是另⼀个元组的“⼦集”),则较短的元组“⼩于”较长的元组
在Python中,这个算法看起来可能有点像这样:
注意,我们永远不会这样编写代码,因为Python已经为我们完成了所有这些⼯作。上⾯整个函数与使⽤
字典排序
这种给予⼀个迭代中第⼀项优先权并类似于按字母顺序的排序⽅式称为字典排序。你不需要知道这个短语,但是如果你需要描述Python中排序的⼯作⽅式,就可以使⽤lexicographic这个词。
字符串和元组是按字典顺序排列的,正如我们所见,列表也是这样:
实际上,Python中的⼤多数序列都应该按字典顺序排列(range对象是⼀个例外,因为根本⽆法对它们进⾏排序)。
但并不是Python中的所有集合都依赖于字典排序。
字典和集合的⽐较
Python中的许多对象都可以进⾏相等⽐较,但不是都能够排序。
例如,字典⽐较“相等”时,它们所有的键和值都相同:
但是字典不能使⽤运算符来排序:
集合也是类似的,除了集合可以使⽤排序运算符……它们只是不使⽤这些运算符来排序:
集合重载了这些运算符,以便回答关于⼀个集合是否是另⼀个集合的⼦集还是超集的问题(请参阅⽂档
中关于集合的部分)。
深度相等
Python中两种数据结构之间的⽐较往往是深度⽐较。⽆论我们是在⽐较列表、元组、集合还是字典,当我们询问其中两个对象是否“相等”时,Python将递归遍历每个⼦对象并询问它们是否“相等”。
因此,给定⼀个字典就可以将其中的元组映射到元组列表:
-
询问两个字典是否相等等价于递归地询问每个键值对是否相等:
字典会问它们的每个键“你在另⼀个字典⾥吗”,然后问这些键对应的每个值“你等于另⼀个值吗”。但是,每⼀个操作都可能(就像在本例中)需要另⼀层深度的操作:键是需要遍历的元组,⽽值是需要遍历的列表。在这种情况下,需要更深⼊地遍历这些值,即列表,因为它们包含更多的数据结构:元组。
不过,我们不必担⼼这些:Python会⾃动地为我们做这些深⼊的⽐较。
虽然你不需要关⼼深度⽐较是怎样进⾏的,但是,实际上Python的⽐较深度是轻易就能知道的。。
例如,如果我们有⼀个带有x、y和z属性的类,我们想要在我们的__eq__⽅法中进⾏⽐较,⽽不是使⽤这个冗长的布尔表达式:
我们可以将这些值处理成含有3个项的元组,来替代布尔表达式进⾏⽐较:
我发现这更易于阅读,主要是因为我们在代码中添加了对称性:我们有⼀个==表达式,它的两边都有相同类型的对象。
深度排序
这种“深度⽐较”适⽤于相等⽐较,但也适⽤于排序。
深度排序的例⼦不如深度相等的例⼦明显,但是确定哪些地⽅可以⽅便地进⾏深度排序可以帮助你极⼤地提⾼代码的可读性。
举个例⼦⽅法:
这个 __lt__⽅法在其类上实现了
上⾯的__lt__⽅法会给予last_name优先权:只有当这两个对象的last_name属性恰好相等时才会检查first_name。
如果我们想打破这个逻辑,我们可以这样重写我们的代码:
或者,我们也可以使⽤元组的深度排序来代替:
在这⾥,我们按照字典顺序(⾸先按照它们的第⼀个项排序)排列元组。我们的元组正好包含字符串,这些字符串也会按字典顺序排序(⾸先按其第⼀个字符排序)。因此,我们对这些对象进⾏了深度排序。
⼀次按多个属性排序
在对Python对象排序时,了解Python序列的词典排序和深度排序⾮常有⽤。从Python的⾓度来看,排序实际上就是⼀遍⼜⼀遍地排列顺序。
Python内置的sorted函数接受⼀个key函数,它可以返回⼀个相应的key对象,并以此来对这些项进⾏排序。
这⾥我们指定了⼀个key函数,它接受⼀个单词并返回⼀个元组,该元组由两部分组成:单词的长度和⼤⼩写规范化的单词:
使⽤上⾯的key函数,我们可以先根据⽔果的长度排序,然后根据它们的⼤⼩写标准化的等价项排序。所以“jujube”排在第⼀位,因为它是6个字母(⽐如longan 和Loquat),但它按字母顺序也是排在longan 和 Loquat之前。
如果我们只是按长度排序,我们会有⼀个不同的顺序:
旁注:在Python中,深度⽐较实际上早于sorted 函数的key参数。在key函数出现之前,Python开发者会创建元组列表,对元组列表进⾏排序,然后从该列表中获取他们关⼼的实际值(⽂档中对此进⾏了讨论)。
元组排序并不只是适⽤sorted函数。任何能看到key函数的地⽅都可以考虑使⽤元组排序。例如min和max函数:
在Python执⾏排序操作的任何地⽅,你都可以使⽤Python数据结构的深度排序。
深度哈希性 (和不可哈希性)
Python既具有深度相等性,⼜具有深度可排序性。但是Python的深度⽐较还不⽌于此:还有深度哈希性。
这主要是由元组带来的的。元组可以⽤作字典中的键(正如我们前⾯看到的),它们可以在集合中使⽤:
但这只适⽤于包含不可变值的元组:
包含列表的元组是不可哈希的,因为列表是不可哈希的:元组⾥边的每个对象都必须是可哈希的,这样元组本⾝才是可哈希的。
因此,虽然包含列表的元组是不可哈希的,但是包含元组的元组是可哈希的:
元组通过分派给它们包含的项的哈希值来计算⾃⾝的哈希值:
python新手代码例子虽然哈希性是⼀个很⼤的主题,但这就是我要说的全部。你不需要真正了解Python中的哈希过程是如何⼯作的,所以如果你发现这⼀部分令⼈困惑,也没有关系!
这⾥的要点是Python⽀持深度哈希,这就是我们可以使⽤元组作为字典键的原因,也是我们可以在集合中使⽤元组的原因。
深度⽐较是⼀种需要记住的⼯具
当你有⼀段以特定顺序⽐较两个基于⼦部分的对象的代码时:
你可以优先考虑元组排序:
如果你正在进⾏很多东西的相等⽐较时:
你或许可以优先考虑深度相等:
如果你需要使⽤⼀个带有由多个部分组成的键的字典时,并且这些部分都是可哈希的,你可以使⽤⼀个元组:
译者:天天向上
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论