【Python学习手册(第四版)】学习笔记11.2-表达式语句(print函数)及打印操作(重定向等)详解

个人总结难免疏漏,请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。

主要介绍表达式语句(print函数)及打印操作(重定向等)。视需要选择目录阅读。


目录

表达式语句

错误示例:原处修改

打印操作

[Python 3.0的print函数](#Python 3.0的print函数)

调用格式

应用

打印流重定向

重定向输出流

自动化流重定向

为什么要注意print和stdout


表达式语句

在Python中,也可以使用表达式作为语句(本身只占一行)。但是表达式结果不会存储,只有当表达式工作并作为附加的效果,这样才有意义。

通常在两种情况下表达式用作语句。

调用函数和方法

有些函数和方法会做很多工作,而不会有返回值。这种函数在其他语言中有时称为过程。因为它们不会返回你可能想保留的值,所以你可以用表达式语句调用这些函数。

在交互模式提示符下打印值

Python会在交互模式命令行中响应输入的表达式的结果。从技术上来讲,这些也是表达式语句。作为输入print语句的简写方法。

表11-4列出Python中一些常见的表达式语句的形式。函数和方法的调用写在函数/方法变量名后的括号内,具有零或多个参数的对象(其实,这就是计算对象的表达式)。

在Python 3.0中,打印是一个函数调用而通常独自编写为一行,并且生成器函数(后续文章介绍)中的yield操作通常也编写为一条语句。

例如,尽管通常在独自一行上运行一个print调用,它像任何其他函数调用一样返回一个值(它的返回值是None,这是那些不返回任何有意义内容的函数的默认返回值):

python 复制代码
>>> x = print('life')
life
>>> print(x)
None

注意:虽然表达式在Python中可作为语句出现,但语句不能用作表达式。

例如,Python不让把赋值语句(=)嵌入到其他表达式中。这样做的理由是为了避免常见的编码错误。当用"=="做相等测试时,不会打成"="而意外修改变量的值。

python 复制代码
>>> print(a = 1)
Traceback (most recent call last):
  File "<pyshell#189>", line 1, in <module>
    print(a = 1)
TypeError: 'a' is an invalid keyword argument for print()
>>> print(a == 1)
False

错误示例:原处修改

这里会引出Python工作中常犯的错误。

表达式语句通常用于执行可于原处修改列表的列表方法:

python 复制代码
>>> l1 = [1,2]
>>> l1.append(3)
>>> l1
[1, 2, 3]

Python初学者时常把这种运算写成赋值语句,试着把L赋值给更大的列表:

python 复制代码
>>> l = l.append(4)
>>> print(l)
None

这样做是行不通的。对列表调用append、sort或reverse这类在原处的修改的运算,一定是对列表做原处的修改,但这些方法在列表修改后并不会把列表返回。

事实上,它们返回的是None对象。如果你赋值这类运算的结果给该变量的变量名,只会丢失该列表(而且可能在此过程中被当成垃圾回收)。

python 复制代码
>>> l

所以不要这样做。


打印操作

在Python中,print语句可以实现打印------只是对程序员友好的标准输出流的接口而已。

从技术角度来讲,这是把一个或多个对象转换为其文本表达形式,然后发送给标准输出或另一个类似文件的流。在Python中,打印与文件和流的概念紧密相连。

文件对象方法

写入文件的文件对象方法(例如,file.write(str))。打印操作是类似的,但更加专注------文件写入方法是把字符串写入到任意的文件,print默认地把对象打印到stdout流,添加了一些自动的格式化。

和文件方法不同,在使用打印操作的时候,不需要把对象转换为字符串。

标准输出流

标准输出流(通常叫做stdout)只是发送一个程序的文本输出的默认的地方。加上标准输入流和错误流,它只是脚本启动时所创建的3种数据连接中的一种。标准输出流通常映射到启动Python程序的窗口,除非它已经在操作系统的shell中重定向到一个文件或管道。

由于标准输出流在Python中可以作为内置的sys模块中的stdout文件对象使用(例如,sys.stdout),用文件的写入方法调用来模拟print成为可能。

然而,print很容易使用,这使得很容易就能把文本打印到其他文件或流。

编写打印操作的方式取决于所使用的Python的版本:

在Python 3.X中,打印是一个内置函数,用关键字参数来表示特定模式。

在Python 2.X中,打印是语句,拥有自己的特定语法。

Python 3.0的print函数

严格地讲,打印不是一种单独的语句形式。

print内置函数通常在其自身的一行中调用,但是它不会返回我们所关心的任何值(从技术上讲,它返回None)。因为它是一个常规的函数。

调用格式

从语法上讲,调用Python 3.0的print函数有如下的形式:

再来看一下源码

在这个正式的表示中,方括号中的项是可选的,并且可能会在一个给定的调用中省略,并且=后面的值都给出了参数的默认值。这个内置的函数把字符串sep所分隔开的一个或多个对象的文本表示,后面跟着的字符串end,都打印到流file中。

sep、end和file部分如果给出的话,必须作为关键字参数给定------也就是说,必须使用一种特殊的"name=value"语法来根据名称而不是位置来传递参数。

发送给这个调用的关键字参数可以以任何的从左到右的顺序显示,这些参数跟在要打印的对象的后面,并且,它们控制print操作:

  • ·sep是在每个对象的文本之间插入的一个字符串,如果没有传递的话,它默认地是一个单个的空格;传递一个空字符串将会抑制分隔符。
  • ·end是添加在打印文本末尾的一个字符串,如果没有传递的话,它默认的是一个\n换行字符。传递一个空字符串将会避免在打印的文本的末尾移动到下一个输入行------下一个print将会保持添加到当前输出行的末尾。
  • ·file指定了文本将要发送到的文件、标准流或者其他类似文件的对象;如果没有传递的话,它默认的是sys.stdout。带有一个类似文件的write(string)方法的任何对象都可以传递,但真正的文件应该已经为了输出而打开。

要打印的每个对象的文本表示,通过把该对象传递给str内置函数调用而获得;这个内置函数针对任何对象返回一个"用户友好的"显示字符串。

没有参数的时候,print函数直接把一个换行字符打印到标准输出流,它通常显示为一个空白的行。

应用

下面把各种对象类型打印到默认的标准输出流,带有一个默认的分隔符和行末格式化添加(这里都是默认值)。

python 复制代码
>>> print()

>>> x = 'spam'
>>> y = 99
>>> z = ['egg']
>>> 
>>> print(x,y,z)
spam 99 ['egg']

这里不需要把对象转换为字符串,而在文件写入方法中则需要这么做。

默认情况下,print调用在打印的对象之间添加一个空格。要取消这个空格,给sep关键字参数发送一个空字符串,或者发送一个自己所选择的替代分隔符:

python 复制代码
>>> print(x,y,z, sep = '') 	    #禁止分离
spam99['egg']

>>> print(x,y,z, sep = ',') 	#这里选择的是中文逗号
spam,99,['egg']
>>> 

**默认情况下,print添加一个行末字符来结束输出行。**可以通过向end关键字参数传递一个空字符串来抑制这一点并避免换行,或者可以传递一个自己的不同的终止符(包含一个\n符号来手动地换行):

python 复制代码
>>> print(x,y,z, end = '')	#禁止分离
spam 99 ['egg']

>>> print(x,y,z, end = '');print(x,y,z)    #两条打印,同一行输出
spam 99 ['egg']spam 99 ['egg']

>>> print(x,y,z, end = '...\n')    #自定义
spam 99 ['egg']...
>>>

也可以组合关键字参数来指定分隔符和行末字符串------它们可以以任何顺序出现,但是必须出现在所有要打印的对象的后面:

python 复制代码
>>> print(x,y,z, sep = '...', end = '!\n')
spam...99...['egg']!
>>> print(x,y,z, end = '!\n', sep = '...')
spam...99...['egg']!

如何使用file关键字 ------它在单个打印的过程中,直接把文本打印到一个输出文件或者其他的可兼容对象(这其实是流重定向的一种形式):

python 复制代码
>>> print(x,y,z, sep = '...', end = '!\n',file = open('data.txt','w'))

>>> print(x,y,z)
spam 99 ['egg']

>>> print(open('data.txt').read())
spam...99...['egg']!

>>> 

print操作提供的分隔符和行末选项只是为了方便起见。

如果需要显示更具体的格式,不要以这种方式打印,相反,提前构建一个更复杂的字符串或者在print自身之中使用字符串工具,并一次性打印该字符串:

python 复制代码
>>> text = '%s: %-.4f,%05d' % ('Result',3.14159,42)
>>> print(text)
Result: 3.1416,00042

>>> print('%s: %-.4f,%05d' % ('Result',3.14159,42))
Result: 3.1416,00042

打印流重定向

打印都默认地发送到标准输出流。通常发送到其他的地方也是有用的,例如发送到一个文本文件,以保存结果供以后使用和测试。事实上,在脚本中重定向一个脚本的流也是很容易做到的。

print语句只是Python的人性化的特性,提供了sys.stdout对象的简单接口,再加上一些默认的格式设置。实际上,如果想写的更复杂一些,也可以用下面这种方式编写打印操作。

python 复制代码
>>> import sys
>>> sys.stdout.write('hello world\n')
hello world
12  #输出位数

这段程序有意调用了sys.stdout的write方法(当Python启动连接输出流的文件对象时,这个属性就会事先设置)。print语句隐藏大多数细节,提供了简单工具从而进行简单的打印任务。

重定向输出流

为什么要教你复杂的打印方式呢?等效的sys.stdout打印方式可以说是Python中常用技术的基础。

通常来说,print和sys.stdout的关系如下:

python 复制代码
>>> print(x,y)
spam 99

#等价于下面

>>> import sys
>>> sys.stdout.write(str(x) + ' ' + str(y) + '\n')
spam 99
8
>>> 

作为较长的打印书写形式本身并没有什么用处。不过了解这就是print语句所做的事是有用处的,因为有可能把sys.stdout重新赋值给标准输出流以外的东西。换句话说,这种等效的方式提供了一种方法,可以让print语句将文字传送到其他地方。例如:

python 复制代码
>>> import sys
>>> sys.stdout = open('log.txt','a')
>>> print(x,y)

在这里,把sys.stdout重设成已打开的文件对象(采用附加模式)。重设之后,程序中任何地方的print语句都会将文字写至文件log.txt的末尾,而不是原始的输出流。print语句将会很乐意持续地调用sys.stdout的write方法,无论sys.stdout当时引用的是什么。因为你的进程中只有一个sys模块,通过这种方式赋值sys.stdout会把程序中任何地方的每个print都进行重新定向。

甚至可以将sys.s tdout重设为非文件的对象,只要该对象有预期的协议(write方法)。当该对象是类时,打印的文字可以定位并通过任意方式进行处理。

这种重设输出列表的技巧主要用于程序原本是用print语句编写的情况。如果一开始就知道应该输出到文件中去,就可以改为调用文件的write方法。

为了将基于print的程序重定向,sys.stdout重设为修改每条print语句或者使用系统shell重定向语法提供一种方便的替代方式。

自动化流重定向

通过赋值sys.stdout而将打印文字重定向的技巧实际上非常常用。但是,上一节代码中有个潜在的问题,那就是没有直接的方式可以保存原始的输出流。

在打印至文件后,可以切换回来。因为sys.stdout只是普通的文件对象,你可以存储它,需要时恢复:

python 复制代码
>>> import sys
>>> temp = sys.stdout    #保存以便恢复
>>> sys.stdout = open('log.txt','a')    #定向打印到文件
>>> print('life')        #打印到文件
>>> sys.stdout.close()   #关闭保存到磁盘
>>> sys.stdout = temp    #恢复原始打印
>>> 

>>> print('life')
life
>>> print(open('log.txt').read())
life

>>> 

像这样的手动保存和恢复原始的输出流包含了相当多的额外工作。因为这种操作出现的相当频繁,一个print扩展功能使得它显得多余。

在Python 3.0中,file关键字允许一个单个的print调用将其文本发送给一个文件的write方法,而不用真正地重设sys.stdout。因为这种重定向是暂时的,普通的print语句还是会继续打印到原始的输出流的。

python 复制代码
>>> log = open('log.txt','a')
>>> x,y,z = 1,2,3
>>> print(x,y,z,file = log)
>>> a,b,c = 'lie'
>>> print(a,b,c)
l i e

如下交互会话使用了两种打印,然后把输出重定向到一个外部文件中,以验证打印了相同的文本:

除非喜欢录入,print操作通常是显示文本的最佳选择。

为什么要注意print和stdout

print语句和sys.stdout之间的等效是很重要的。这样才有可能把sys.stdout重新赋值给用户定义的对象(提供和文件相同的方法,就像write)。

因为print语句只是传送文本给sys.stdout.write方法,可以把sys.stdout赋值给一个对象,而由该对象的write方法通过任意方式处理文字,通过这个对象捕捉程序中打印的文本。

例如,你可以传送打印的文字给GUI窗口,或者定义一个有write方法的对象,它会做所需要的发送工作,从而可以提供给多个目的地。

行得通是因为print是多态运算:sys.stdout是什么不重要,只要有个方法(接口)称为write即可。

不再需要刻意重设sys.stdout------常规的print仍然定向到stdout流:

Python内置的raw_input()函数会从sys.stdin文件读入,可以用类似方式拦截对读取的请求:使用类来实现类似文件的read方法。

注意:因为打印的文字进入stdout流,这也是在CGI脚本中打印HTML的方式。这也可以在操作系统命令行中对Python脚本的输入和输出进行像往常一样的重定向:

Python的打印操作重定向工具实质上是这些Shell语法形式的纯Python替代。

相关推荐
ROBOT玲玉11 分钟前
Milvus 中,FieldSchema 的 dim 参数和索引参数中的 “nlist“ 的区别
python·机器学习·numpy
虾球xz1 小时前
游戏引擎学习第55天
学习·游戏引擎
Kai HVZ1 小时前
python爬虫----爬取视频实战
爬虫·python·音视频
古希腊掌管学习的神1 小时前
[LeetCode-Python版]相向双指针——611. 有效三角形的个数
开发语言·python·leetcode
m0_748244831 小时前
StarRocks 排查单副本表
大数据·数据库·python
oneouto1 小时前
selenium学习笔记(二)
笔记·学习·selenium
B站计算机毕业设计超人1 小时前
计算机毕业设计PySpark+Hadoop中国城市交通分析与预测 Python交通预测 Python交通可视化 客流量预测 交通大数据 机器学习 深度学习
大数据·人工智能·爬虫·python·机器学习·课程设计·数据可视化
路人甲ing..1 小时前
jupyter切换内核方法配置问题总结
chrome·python·jupyter
sealaugh321 小时前
aws(学习笔记第十九课) 使用ECS和Fargate进行容器开发
笔记·学习·aws
游客5201 小时前
opencv中的常用的100个API
图像处理·人工智能·python·opencv·计算机视觉