聊聊 print 的宿世今生
本文原创并首发于群众号【Python猫】,未担当权,请勿转载。
原文地点:
https://mp.weixin.qq.com/s/NuzfuH_zCZzcrmSFR04NHw
(一)
上周,我翻译了一篇文章,表明了为什么 Python 3 把 print 改为函数? 归纳有如下几点缘故:1、print 不相宜作为使用步骤级的语句。2、改为一个函数,可以完成更繁复的功效。3、改为一个函数,能便利地举行交换。
在 Python 2 中,print 是个语句(statement),它的级别就跟 for、if、def 等紧张字相反,这是一个新鲜的计划(毕竟 Python 诞生于 1989 年),改成 print() 函数,意味着它晋级了。
在查阅材料的时分,我发觉 print 在历代版本中,不休提高厘革,到了今天,它本身已充足完满了,但是外部的挑唆不休不休。
因此,这篇文章再来聊聊它:先容 print 的现状,追溯它的汗青,说说它的挑唆者,挖挖那些愈加实质的东西。
(二)
在 3.0 版本中,print() 函数全新下场,开发者可以自界说打印目标的距离(默许是空格)、停止办法(默许是换行)、以及输入地点(默许是标准输入 sys.stdout)。
而到了 3.3 版本,它还添加了一个新的参数,可以决定对否要改造数据流。
至此,这个函数的完备格式就变成了 print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False) ,与晋级前的 print 语句是大相径庭啦。
优点是不言而喻的,可定制的参数带来了使用场景的扩展。
(三)
但是,在这次大版本的窜改之前,早前的 print 语句并非是刻舟求剑的,中心开发者们不休在完满它。
比如,在 2000 年的 PEP-214 之前,print 语句只能用于标准输入(sys.stdout),仅有当提出这个提案后,print 才可以打印内容到类文件目标(file-like object)中。
(注:PEP 即 Python 改良提案,更多先容详见旧文《学习Python,怎能不懂点PEP呢?》)
这次调停后,它的写法可以如下(此中,mylogfile 是用于纪录打印信息的文件途径):
print >> mylogfile, 'this message goes to my log file'
在只交往过 Python 3 的同砚眼里,这个写法约莫很别扭吧,但是它同等于如今的:
print('this message goes to my log file', file = mylogfile)
(四)
上例是一次告捷的改良,但幽默的是,社区内也有一次失败的修正提案。
与 print() 函数相反,print 语句在打印完一个目标后,默许会换行,因此,当打印的内容自带了换行符的时分,终极的打印后果就会显现一个多余的换行。
2001 年的时分,有开发者在 PEP-259 中发起,依据打印的最初一个字符的典范,设置几个标志位,以此决定对否要默许换行。校验端正如下:
- -1 ——假如最初一个目标是以换行符完毕的字符串
- 0 ——假如最初一个目标是以空缺字符开头的字符串,既不是空格也不是换行符
- 1 ——在一切别的情况下(包含最初一个目标是空字符串或不是字符串的情况)
依据这些端正,print 语句碰到 -1 标志位的时分,就不再做默许的换行了,仿佛可以处理多余换行的成绩。
但是,这个提案被反对了。反对的意见主要是:如此约莫会毁坏掉多数个 CGI 脚本,并且 Python 中以前有太多的“邪术”了。
这一套端正的确太神奇了,幸亏没有实行。在如今的版本中,只需调停 end 参数,就可以制止多余换行的成绩。
(五)
阅读过往的 PEP 文档,就是在阅读 Python 的汗青,从中你可以看到计划者们对功效细节的打磨历程,终极你就明白了,Python 是怎样一步一步地提高成今天的样子。
不外,汗青中除了能看到精华,也可以看到一些包袱。print() 函数的晋级就是在甩偷换袱,前不久我写了《聊聊 Python 的内置电池》,聊到了 Python 中废弃局部标准库的话题,也是一个很好的察看例子。
除此之外,“print”的定名本身也算是一种包袱。
早前的盘算机使用纸带作为信息载体,步骤的运算后果必要 print 在纸带上,以是顺理成章地,有些编程言语就使用了“print”来表现步骤的输入利用。只管厥后不再使用纸带了,一些言语仍旧延用这个词,比如 C 言语以及参考了 C 言语的 Python。
Python 的另一个参考目标是 Shell,这是一种新鲜的脚本言语,可它没有“print”的包袱,它用的是 echo。这个词的本意是回声,厥后也指雷达的回波,被用于盘算机编程中,则又被赋予了“应对、回显”之义,更直白的表述应该是“输入、打印”。
Python 从 C 中借用了“print”定名,又从 Shell 中借用语句式的表达,构成了本人 print 语句,如今到了新的版本,它去除了语句式的表达,却仍保存着原始定名,可以说这个包袱是永久脱不掉了。
但是,话说归来回头,词语在演化历程中会取得新的生命,它的意义全在于怎样使用。以是,固然没有了纸带这个物理载体,print 这个词却“洗面革心”地活了下去。
它还拥有很多的表兄弟姐妹呢,十分繁华(试试你能认出几个?):
print("点个赞吧!") printf("点个赞吧!"); print_r('点个赞吧!'); var_dump('点个赞吧!'); NSLog(@"点个赞吧!"); System.out.println("点个赞吧!"); console.log("点个赞吧!"); cout << "点个赞吧!" << endl; Console.WriteLine("点个赞吧!"); writeln('点个赞吧!') fmt.Println("点个赞吧!"); Response.Write("点个赞吧!"); alert("点个赞吧!") echo "点个赞吧!" puts "点个赞吧!" say "点个赞吧!";
(六)
言语内里的提高汗青,以及不同言语的相似表述,都标明着一件事,那就是打印利用很紧张,并且我们对它的要求还很繁复多样。
Python 中的 print 语句能提高成今天的 print() 函数,以前十分完满了。
不外,需求是无尽头的,作为最常用的调试伎俩,print() 还达不到完善无缺。它的利益是简便直白、容易上手,但缺陷则是功效单一、听从较低,在必要定制格式的经常使用场景下,不堪大用。
这在不同编程言语中是通病,因此各位都默契地提供了用于调试的日志模块,比如 Java 的 log4j,C++ 的 log4cxx,固然另有 Python 的 logging。
日志模块 logging 可以说是对 print() 函数的交换式晋级,主要优点是愈加机动高效,比如可以设置不同的日志品级、设置多样的格式化信息、乃至可以输入日志到长程办事器上。
固然,日志模块只是一种处理方案,也并不是最完善的。
在 Python 中另有一些模块可以用于调试,比如最主流的 pdb,它可以设置断点、分步伐试、查察栈片断、动态调值等,用得好,有奇效。主流的 IDE 东西也都提供了一些调试伎俩,比拟于简便的 print(),它们具有降维打击的上风。
本年 4 月,Github 上开源了一个自用于调试步骤的库,名叫 PySnooper ,短短两个月,它就劳绩了近 12K 个眷注。这个三方库的标语是“Never use print for debugging again”,其目标就是在调试代码时完全交换 print。
这个库的用法十分简便,只需一行代码,就可以完成对整个函数的监听,做到纪录每一行的实行时间、纪录每个变量的赋值等等,并且还可以使用“with”语句,监听局部的代码块,大概使用“watch”下令,专门监听特定的变量值。
这个库强壮而冷艳,除了上述作用,它还能监听指定格式开头的代码,能在多线程中监听线程,乃至支持用户自界说的监听端正。难怪它一经面世,就好评如潮,各位奔波相告。
snoop 这个单词很故意思,它指的是嗅探、窥伺和监听。首字母大写的 Snoop ,译作史努比,则是一只被很多人喜好的漫画小狗。以是这个 PySnooper 库就令我不由地产生了一种遐想:它是一只嗅觉特别敏锐的小狗,明白无误地为你实行种种监听职责。
史努比小狗(图片泉源于网络)
(七)
最初,我们可以往返忆一下 print 的提高汗青了,有两条线索,一条是它本身提高的明线,另一条是它的挑唆者们的暗线。
先看明线吧,早前版本的 print 语句带有 C 和 Shell 的影子,它是个使用步骤级的 statement,使用十几年间,有过一些改良的实验,比如 PEP-214 和 PEP-259;到了 2009 年的大版本 3.0,Python 把 print 语句改成了 print() 函数,使它成为了浩繁内置函数的一员,随后在 3.3 版本,又对它做了一次功效加强,至此,它完成了本人的华丽蜕变,占据了安定的一席之地。
至于暗线,print 的竞争对手们可谓浩繁,像传统的日志模块 logging、调试模块 pdb、以及主流 IDE 的调试功效,等等,如今另有一位后起之秀 PySnooper,无不对准了 print 的地点,摩拳擦掌,虎视眈眈。
print 一词最早应该跟纸带干系,用处和需求场景都很少,如今的盘算机天下以前不成相提并论,以是才促进了 print 本身的提高,也兴奋了浩繁对手们的崛起。
print 代表了一种诉求/头脑:输入盘算后果、纪录步骤历程、监察目标厘革,然后用于查察、分析、调试、展现等等。
明线上的提高,就是承继了它的名字,强壮 print;暗线上的提高,则是承继了它的头脑,为了完成目标,各施伎俩,百花齐放。
print 固然不是 Python 所特有的,这明暗两线的提高也同理,假如你把视野放就职何一个经得起时间磨练的言语上,一定也会看到相似的提高历程与竞争故事。
最初,假如你想了解更多内容,可经过以下链接查察:
https://docs.python.org/3/library/functions.html#print
学习Python,怎能不懂点PEP呢?
https://www.python.org/dev/peps/pep-0214/
https://www.python.org/dev/peps/pep-0259/
为什么 Python 3 把 print 改为函数?
https://github.com/cool-RR/PySnooper
群众号【Python猫】, 本号连载优质的系列文章,有喵星哲学猫系列、Python进阶系列、好书保举系列、武艺写作、优质英文保举与翻译等等,接待眷注哦。