作者:猫下豌豆花来源:Python猫我想到了一个特殊的写法,很多人会用它来代替pass语句。文章发表后,果然有3条评论提到了它。所谓特殊的写法如下:用...代替passdeffoo():...是中文标点符号的半个省略号,即由英文的3个点组成。如果您是第一次看到它,您可能会想:这东西是怎么回事?PS:如果你知道,仔细看完这篇文章,你可能也会觉得奇怪!1.了解“...”内置常量。其实它是Python3中的一个内置对象,它有一个正式的名字叫Ellipsis,中文翻译为“省略号”。更准确地说,它是一个内置常量(Built-inConstant),6个内置常量之一(其他分别是None、False、True、NotImplemented、__debug__)。关于这个物体的基本性质,下面截图,大家应该能明白我的意思:“……”并不神秘,它只是一个象征性的物体,可能很少见。将pass换成它在语法上不会报错,因为Python允许一个对象不被赋值引用。严格来说,这是异端和语义上站不住脚的——把“...”或其他常量或赋值变量放在一个空的缩进代码块中,它们与动作无关,只能表达“这里是一个无用的对象,不要担心它”。Python允许这些实际上没有用到的对象存在,但是聪明的IDE应该给个提示(我用的是Pycharm),比如告诉你:Statementseemstohavenoeffect。但是“...”常量似乎被特殊对待,并且在我的IDE中没有任何提示。很多人已经习惯像pass一样把它当作空操作来使用(在最先介绍它的邮件组讨论中,给出了这种用法的例子)。但我还是倾向于用pass,你怎么看?2.奇怪的Ellipsis和...在PEP-3100中被引入,并首先被纳入Python3.0版本,而Ellipsis在更早的版本中被包含。虽然官方说是同一个对象的两种写法,说是单例(singleton),但是我也发现了一个很奇怪的现象,和文档的描述相冲突:如你所见,赋值到。..会报错SyntaxError:cannotassigntoEllipsis,但是Ellipsis可以赋值,它们的行为根本不同!被赋值后,Ellipsis的内存地址和类型属性发生了变化,它变成了一个“变量”,而不是常量。相比之下,给True或None等常量赋值时,会报错SyntaxError:cannotassigntoXXX,而给NotImplemented常量赋值则不会报错。众所周知,布尔对象(True/False)在Python2中也可以赋值,但是Python3将它们转变为不可修改的。所以有一个可能的解释:Ellipsis和NotImplemented是Python2时代的遗物,为了兼容性或者只是因为核心开发者遗漏了它们,所以在当前版本(3.8)中仍然可以通过赋值来修改它们。...诞生于Python3时代,未来可能会完全取代Ellipsis。两者目前并存,它们不一致的行为值得我们关注。我的建议:就好像Ellipsis已经死了一样使用“...”。3.为什么要用“...”对象?接下来,我们回到标题问题:Python为什么要使用“...”对象?这里我们只关注Python3的“……”,而没有回溯Ellipsis的历史和现状。我问这个问题的目的是想知道:它有什么用,解决什么问题?从而窥视Python语言设计的更多细节。大概有以下几种回答:(1)扩展切片语法的官方文档是这样描述的:Specialvaluemostlyusedmostlywithextendedslicingsyntaxforuser-definedcontainerdatatypes。这是一个特殊的值,通常后面跟扩展切片语法结合,用在自定义数据类型容器上。文档中没有给出具体的实现示例,但是结合内置函数__getitem__()和slice()使用,可以实现类似[1,...,7]得到7个切片的效果的数字。由于主要用于数据操作,所以大部分人接触的可能比较少。我听说Numpy在一些语法糖用法中使用它。如果你正在使用Numpy,你可以探索一下有哪些方法?(2)表达“未完成的代码”语义...可以作为占位符,也就是我在《Python 为什么要有 pass 语句?》中提到的pass。这个在之前的文章中已经部分分析过了。有人认为这很可爱,而且这个想法得到了Python之父Guido的支持:(3)TypeHint用法Python3.5引入的TypeHint是“...”的主要使用场合。可以表示变长的参数,比如Tuple[int,...]表示一个元素为int类型的元组,但个数不限。它还可以表示不确定的变量类型,例如文档中给出的示例:fromtypingimportTypeVar,GenericT=TypeVar('T')deffun_1(x:T)->T:...#Theredeffun_2(x:T)->T:...#和这里可能不同fun_1(1)#这样可以,T被推断为intfun_2('a')#这样也可以,现在T函数定义是str无法确定当调用函数时,T的实际类型在调用函数时确定。在.pyi文件中,...无处不在。这是一个存根文件(stubfile),主要用来存放Python模块的类型提示信息,为mypy和pytype等类型检查工具和IDE提供静态代码检查。(4)表达无限循环最后,我觉得有一个很终极的原因,除了引入“……”来表达,没有更好的办法。我们先来看两个例子:两个例子的结果中都出现了“...”,代表什么?对于列表和字典等容器,如果它们的内部元素是可变对象,则它们存储对可变对象的引用。然后,当它的内部元素引用容器本身时,就会递归地发生无限循环引用。无法详尽地表达无限循环。Python用...来表达,更加形象易懂。除此之外,恐怕没有更好的选择了。最后总结一下本文的内容:...是Python3中的一个内置常量,它是一个单例对象。虽然它是Python2中Ellipsis的别称,但它的本质已经与旧对象分道扬镳……可以作为占位符代替pass语句,但作为常量对象,占位符语义并不严格。很多人已经习惯性的接受了,那为什么不用呢……在Python的很多使用场景中,除了占位符的使用,它还可以支持扩展的切片语法,丰富的TypeHint类型检查,容器对象的无限表示循环...对于大多数人来说,它可能并不常见(有些人可能会拒绝它,因为它是符号的特例),但它的存在有时可以带来便利。希望这篇文章能让更多的人知道,那么文章的目的就达到了~
