首页 >后端开发 >Python教程 >[译]The Python Tutorial#Input and Output

[译]The Python Tutorial#Input and Output

PHP中文网
PHP中文网原创
2017-07-10 18:13:241243浏览

[译]The Python Tutorial#Input and Output

Python中有多种展示程序输出的方式;数据可以以人类可读的方式打印出来,也可以输出到文件中以后使用。本章节将会详细讨论。

7.1 Fancier Output Formatting

目前为止已经介绍过两种输出值的方式:表达式语句print()函数。(第三种方式是使用对象的write()方法;使用sys.stdout引用标准输出文件。详细信息参考库文件参考手册。)

有时候需要对输出有更多的控制,而不是简单的使用空格分开值。有两种方式格式化输出:第一种方式是手动处理字符串,使用字符串的切片和连接操作,创建任何可以想象到的输出布局。字符串类型提供了一些将字符串填充到指定列宽的有用方法,马上会讨论这点。第二种方式是使用格式化字符串或者str.format()方法。

string模块包含Template类,该类提供向字符串代入值的方法。

当然还有一个问题:如何将值转换为字符串?Python提供了将任何值转换为字符串的方法:将值传递给repr()或者str()函数即可。

str()函数返回值的人类可读的形式,而repr()生成值的解释器可读形式(如果没有等价语法,将会强制抛出SyntaxError)。对于没有提供特定适应人类阅读形式的对象,str()函数会返回与repr()相同的值。许多值使用str()repr()函数将得到相同的返回值,如数字或者像列表和字典的结构体。特别地,字符串有两种区别明显的表示形式。

以下是一些示例:

<code class="sourceCode python"><span class="op">>>></span> s <span class="op">=</span> <span class="st">'Hello, world.'</span>
<span class="op">>>></span> <span class="bu">str</span>(s)
<span class="co">'Hello, world.'</span>
<span class="op">>>></span> <span class="bu">repr</span>(s)
<span class="co">"'Hello, world.'"</span>
<span class="op">>>></span> <span class="bu">str</span>(<span class="dv">1</span><span class="op">/</span><span class="dv">7</span>)
<span class="co">'0.14285714285714285'</span>
<span class="op">>>></span> x <span class="op">=</span> <span class="dv">10</span> <span class="op">*</span> <span class="fl">3.25</span>
<span class="op">>>></span> y <span class="op">=</span> <span class="dv">200</span> <span class="op">*</span> <span class="dv">200</span>
<span class="op">>>></span> s <span class="op">=</span> <span class="st">'The value of x is '</span> <span class="op">+</span> <span class="bu">repr</span>(x) <span class="op">+</span> <span class="st">', and y is '</span> <span class="op">+</span> <span class="bu">repr</span>(y) <span class="op">+</span> <span class="st">'...'</span>
<span class="op">>>></span> <span class="bu">print</span>(s)
The value of x <span class="op">is</span> <span class="fl">32.5</span>, <span class="op">and</span> y <span class="op">is</span> <span class="dv">40000</span>...
<span class="op">>>></span> <span class="co"># The repr() of a string adds string quotes and backslashes:</span>
... hello <span class="op">=</span> <span class="st">'hello, world</span><span class="ch">\n</span><span class="st">'</span>
<span class="op">>>></span> hellos <span class="op">=</span> <span class="bu">repr</span>(hello)
<span class="op">>>></span> <span class="bu">print</span>(hellos)
<span class="co">'hello, world\n'</span>
<span class="op">>>></span> <span class="co"># The argument to repr() may be any Python object:</span>
... <span class="bu">repr</span>((x, y, (<span class="st">'spam'</span>, <span class="st">'eggs'</span>)))
<span class="co">"(32.5, 40000, ('spam', 'eggs'))"</span></code>

有两种方式输出一个平方和立方表格:

<code class="sourceCode python"><span class="op">>>></span> <span class="cf">for</span> x <span class="op">in</span> <span class="bu">range</span>(<span class="dv">1</span>, <span class="dv">11</span>):
...     <span class="bu">print</span>(<span class="bu">repr</span>(x).rjust(<span class="dv">2</span>), <span class="bu">repr</span>(x<span class="op">*</span>x).rjust(<span class="dv">3</span>), end<span class="op">=</span><span class="st">' '</span>)
...     <span class="co"># Note use of 'end' on previous line</span>
...     <span class="bu">print</span>(<span class="bu">repr</span>(x<span class="op">*</span>x<span class="op">*</span>x).rjust(<span class="dv">4</span>))
...
 <span class="dv">1</span>   <span class="dv">1</span>    <span class="dv">1</span>
 <span class="dv">2</span>   <span class="dv">4</span>    <span class="dv">8</span>
 <span class="dv">3</span>   <span class="dv">9</span>   <span class="dv">27</span>
 <span class="dv">4</span>  <span class="dv">16</span>   <span class="dv">64</span>
 <span class="dv">5</span>  <span class="dv">25</span>  <span class="dv">125</span>
 <span class="dv">6</span>  <span class="dv">36</span>  <span class="dv">216</span>
 <span class="dv">7</span>  <span class="dv">49</span>  <span class="dv">343</span>
 <span class="dv">8</span>  <span class="dv">64</span>  <span class="dv">512</span>
 <span class="dv">9</span>  <span class="dv">81</span>  <span class="dv">729</span>
<span class="dv">10</span> <span class="dv">100</span> <span class="dv">1000</span>

<span class="op">>>></span> <span class="cf">for</span> x <span class="op">in</span> <span class="bu">range</span>(<span class="dv">1</span>, <span class="dv">11</span>):
...     <span class="bu">print</span>(<span class="st">'</span><span class="sc">{0:2d}</span><span class="st"> </span><span class="sc">{1:3d}</span><span class="st"> </span><span class="sc">{2:4d}</span><span class="st">'</span>.<span class="bu">format</span>(x, x<span class="op">*</span>x, x<span class="op">*</span>x<span class="op">*</span>x))
...
 <span class="dv">1</span>   <span class="dv">1</span>    <span class="dv">1</span>
 <span class="dv">2</span>   <span class="dv">4</span>    <span class="dv">8</span>
 <span class="dv">3</span>   <span class="dv">9</span>   <span class="dv">27</span>
 <span class="dv">4</span>  <span class="dv">16</span>   <span class="dv">64</span>
 <span class="dv">5</span>  <span class="dv">25</span>  <span class="dv">125</span>
 <span class="dv">6</span>  <span class="dv">36</span>  <span class="dv">216</span>
 <span class="dv">7</span>  <span class="dv">49</span>  <span class="dv">343</span>
 <span class="dv">8</span>  <span class="dv">64</span>  <span class="dv">512</span>
 <span class="dv">9</span>  <span class="dv">81</span>  <span class="dv">729</span>
<span class="dv">10</span> <span class="dv">100</span> <span class="dv">1000</span></code>

(第一个例子中,列之间的那个空格是由print()自动添加的:该函数在输出时总是在参数之间插入空格)

这个例子演示了string对象的str.rjust()方法,这个方法使字符串在给定宽度的列中向右对齐,在左边添加空格。str.ljust()str.center()是相似的方法。这些方法并不会改变原来的字符串,只是返回一个新的字符串。如果输入的字符串太长,这些方法并不会截断字符串,而是不改变字符串并返回;虽然这样会使得列布局混乱,但是总比输出不真实的值好。(若实在想截断可以使用切片操作,如:x.ljust(n)[:n]。)

方法str.zfill()在数字字符串左侧添加零,可以识别正负号:

<code class="sourceCode python"><span class="op">>>></span> <span class="st">'12'</span>.zfill(<span class="dv">5</span>)
<span class="co">'00012'</span>
<span class="op">>>></span> <span class="st">'-3.14'</span>.zfill(<span class="dv">7</span>)
<span class="co">'-003.14'</span>
<span class="op">>>></span> <span class="st">'3.14159265359'</span>.zfill(<span class="dv">5</span>)
<span class="co">'3.14159265359'</span></code>

str.format()的基础使用方式是:

<code class="sourceCode python"><span class="op">>>></span> <span class="bu">print</span>(<span class="st">'We are the {} who say "{}!"'</span>.<span class="bu">format</span>(<span class="st">'knights'</span>, <span class="st">'Ni'</span>))
We are the knights who say <span class="st">"Ni!"</span></code>

传入str.format()中的对象会替换掉花括号和其中的字符(称作格式化域)。花括号中的数字可以用来匹配传入str.format()的对象列表相应位置的对象。

<code class="sourceCode python"><span class="op">>>></span> <span class="bu">print</span>(<span class="st">'</span><span class="sc">{0}</span><span class="st"> and </span><span class="sc">{1}</span><span class="st">'</span>.<span class="bu">format</span>(<span class="st">'spam'</span>, <span class="st">'eggs'</span>))
spam <span class="op">and</span> eggs
<span class="op">>>></span> <span class="bu">print</span>(<span class="st">'</span><span class="sc">{1}</span><span class="st"> and </span><span class="sc">{0}</span><span class="st">'</span>.<span class="bu">format</span>(<span class="st">'spam'</span>, <span class="st">'eggs'</span>))
eggs <span class="op">and</span> spam</code>

str.format()中可以使用关键字参数,使用参数名引用对应的值:

<code class="sourceCode python"><span class="op">>>></span> <span class="bu">print</span>(<span class="st">'This </span><span class="sc">{food}</span><span class="st"> is </span><span class="sc">{adjective}</span><span class="st">.'</span>.<span class="bu">format</span>(
...       food<span class="op">=</span><span class="st">'spam'</span>, adjective<span class="op">=</span><span class="st">'absolutely horrible'</span>))
This spam <span class="op">is</span> absolutely horrible.</code>

可以结合位置参数和关键字参数:

<code class="sourceCode python"><span class="op">>>></span> <span class="bu">print</span>(<span class="st">'The story of </span><span class="sc">{0}</span><span class="st">, </span><span class="sc">{1}</span><span class="st">, and </span><span class="sc">{other}</span><span class="st">.'</span>.<span class="bu">format</span>(<span class="st">'Bill'</span>, <span class="st">'Manfred'</span>,
                                                       other<span class="op">=</span><span class="st">'Georg'</span>))
The story of Bill, Manfred, <span class="op">and</span> Georg.</code>

!a(对应ascii()),!s(对应str())以及!r(对应repr()),用于在格式化之前转换值:

<code class="sourceCode python"><span class="op">>>></span> contents <span class="op">=</span> <span class="st">'eels'</span>
<span class="op">>>></span> <span class="bu">print</span>(<span class="st">'My hovercraft is full of {}.'</span>.<span class="bu">format</span>(contents))
My hovercraft <span class="op">is</span> full of eels.
<span class="op">>>></span> <span class="bu">print</span>(<span class="st">'My hovercraft is full of {!r}.'</span>.<span class="bu">format</span>(contents))
My hovercraft <span class="op">is</span> full of <span class="st">'eels'</span>.</code>

在格式化域后可以跟可选的:以及格式化命令,允许对值的格式化进一步控制。以下示例指定PI的精度为3位:

<code class="sourceCode python"><span class="op">>>></span> <span class="im">import</span> math
<span class="op">>>></span> <span class="bu">print</span>(<span class="st">'The value of PI is approximately </span><span class="sc">{0:.3f}</span><span class="st">.'</span>.<span class="bu">format</span>(math.pi))
The value of PI <span class="op">is</span> approximately <span class="fl">3.142</span>.</code>

:后跟一个整数可以指定格式化域的最小宽度。在制作表格时这很有用:

<code class="sourceCode python"><span class="op">>>></span> table <span class="op">=</span> {<span class="st">'Sjoerd'</span>: <span class="dv">4127</span>, <span class="st">'Jack'</span>: <span class="dv">4098</span>, <span class="st">'Dcab'</span>: <span class="dv">7678</span>}
<span class="op">>>></span> <span class="cf">for</span> name, phone <span class="op">in</span> table.items():
...     <span class="bu">print</span>(<span class="st">'</span><span class="sc">{0:10}</span><span class="st"> ==> </span><span class="sc">{1:10d}</span><span class="st">'</span>.<span class="bu">format</span>(name, phone))
...
Jack       <span class="op">==></span>       <span class="dv">4098</span>
Dcab       <span class="op">==></span>       <span class="dv">7678</span>
Sjoerd     <span class="op">==></span>       <span class="dv">4127</span></code>

如果有一个长的字符串并不想做分离,可以使用名字而不是位置来引用变量。简单的传递一个字典,并且使用中括号来访问键:

<code class="sourceCode python"><span class="op">>>></span> table <span class="op">=</span> {<span class="st">'Sjoerd'</span>: <span class="dv">4127</span>, <span class="st">'Jack'</span>: <span class="dv">4098</span>, <span class="st">'Dcab'</span>: <span class="dv">8637678</span>}
<span class="op">>>></span> <span class="bu">print</span>(<span class="st">'Jack: </span><span class="sc">{0[Jack]:d}</span><span class="st">; Sjoerd: </span><span class="sc">{0[Sjoerd]:d}</span><span class="st">; '</span>
...       <span class="st">'Dcab: </span><span class="sc">{0[Dcab]:d}</span><span class="st">'</span>.<span class="bu">format</span>(table))
Jack: <span class="dv">4098</span><span class="op">;</span> Sjoerd: <span class="dv">4127</span><span class="op">;</span> Dcab: <span class="dv">863767</span></code>

也可以使用**将字典拆包为关键字参数:

<code class="sourceCode python"><span class="op">>>></span> table <span class="op">=</span> {<span class="st">'Sjoerd'</span>: <span class="dv">4127</span>, <span class="st">'Jack'</span>: <span class="dv">4098</span>, <span class="st">'Dcab'</span>: <span class="dv">8637678</span>}
<span class="op">>>></span> <span class="bu">print</span>(<span class="st">'Jack: </span><span class="sc">{Jack:d}</span><span class="st">; Sjoerd: </span><span class="sc">{Sjoerd:d}</span><span class="st">; Dcab: </span><span class="sc">{Dcab:d}</span><span class="st">'</span>.<span class="bu">format</span>(<span class="op">**</span>table))
Jack: <span class="dv">4098</span><span class="op">;</span> Sjoerd: <span class="dv">4127</span><span class="op">;</span> Dcab: <span class="dv">8637678</span></code>

built-in函数vars()返回将当前局部变量作为字典返回,结合vars()使用时,以上特别有用。

参考Format String Syntax,完全了解str.format()

7.1.1 Old string formatting

可以使用%操作符格式化字符串。这种方式像sprintf()风格一样解析%左边的格式化参数,并将右边的参数应用到左边,然后返回格式化后的字符串。示例:

<code class="sourceCode python"><span class="op">>>></span> <span class="im">import</span> math
<span class="op">>>></span> <span class="bu">print</span>(<span class="st">'The value of PI is approximately </span><span class="sc">%5.3f</span><span class="st">.'</span> <span class="op">%</span> math.pi)
The value of PI <span class="op">is</span> approximately <span class="fl">3.142</span>.</code>

更多信息参见printf-style String Formatting 章节。

7.2 Reading and Writing Files

open()函数返回文件对象(file object),通常使用两个参数调用:open(filename, mode)

<code class="sourceCode python"><span class="op">>>></span> f <span class="op">=</span> <span class="bu">open</span>(<span class="st">'workfile'</span>, <span class="st">'w'</span>)</code>

第一个参数是文件的字符串路径。第二个参数是包含几个字符的字符串,描述文件的使用方式。模式r用于读;w只用于写(存在的同名文件将会被删除);a打开文件追加内容,所有写到文件中的内容都会自动添加到文件末尾;r+打开文件可读可写。模式参数是可选的,r是默认模式参数。

通常,文件以文本模式打开,意味着可以从文件中读写字符串,字符串以特定的格式编码。如果没有指定字符编码,那默认值是平台相关的编码(参见open())。追加到模式参数的b指定文件以二进制模式打开:数据以字节对象的形式读写。这种模式用于不包含文本的文件。

文本模式中,读文件时默认将平台特定的行尾结束符(Unix中的\n,Windows中的\r\n)转换为\n。以文本模式写文件时,默认将所有出现的\n转换为平台特定的行尾结束符。这种暗地修改文件数据对于文本文件没有影响,但是会损坏JPEG或者EXE之类的文件的数据。使用二进制模式读写这类文件是要谨慎。

处理文件对象时使用with是比较好的实践。好处是当操作完成后文件可以恰当关闭,即使有异常发生。使用with比使用与其等价的try-finally语句块也简洁得多:

<code class="sourceCode python"><span class="op">>>></span> <span class="cf">with</span> <span class="bu">open</span>(<span class="st">'workfile'</span>) <span class="im">as</span> f:
...     read_data <span class="op">=</span> f.read()
<span class="op">>>></span> f.closed
<span class="va">True</span></code>

如果没有使用with关键字,必须手动调用f.close()方法关闭文件,立即释放占用的系统资源。如果没有明确关闭文件,Python的垃圾收集程序最终会销毁对象并关闭文件,但是这之前文件会保持打开状态一段时间。另一个风险是不同的Python解释器实现会在不同的时刻做回收操作。

文件对象关闭后,无论通过with语句还是使用f.close()试图使用文件对象都会失败:

<code class="sourceCode python"><span class="op">>>></span> f.close()
<span class="op">>>></span> f.read()
Traceback (most recent call last):
  File <span class="st">"<stdin>"</span>, line <span class="dv">1</span>, <span class="op">in</span> <span class="op"><</span>module<span class="op">></span>
<span class="pp">ValueError</span>: I<span class="op">/</span>O operation on closed <span class="bu">file</span></code>

7.2.1 Methods of File Objects

这个章节以下的示例中,假设已经创建了一个叫做f的文件对象。

使用f.read(size)读取文件内容,该方法读取指定数量数据并作为字符串(文本模式)或者字节对象(二进制模式)返回。size是可选的数字参数。size省略或者为负数时,会读取整个文件内容并且返回,如果文件大小比机器内存要大时,全部读取会产生问题。若指定size,至多size大小的字节被读取并返回。如果读到了文件末尾,f.read()返回空字符串('')。

<code class="sourceCode python"><span class="op">>>></span> f.read()
<span class="co">'This is the entire file.\n'</span>
<span class="op">>>></span> f.read()
<span class="co">''</span></code>

f.readline()从文件中读取单行,读取到的字符串末尾会自动加上换行符(\n),只有当文件不以换行符结尾时,读取到文件的最后一行才不会自动加'\n'。这样使得返回值不会含糊不清,如果f.readline()返回空字符串时,那么就读到了文件末尾,而空行则返回\n表示,这是一个只包含单个换行符的字符串。

<code class="sourceCode python"><span class="op">>>></span> f.readline()
<span class="co">'This is the first line of the file.\n'</span>
<span class="op">>>></span> f.readline()
<span class="co">'Second line of the file\n'</span>
<span class="op">>>></span> f.readline()
<span class="co">''</span></code>

使用迭代文件对象的方式,从文件中读取行。这种方式内存高效,快速,代码简洁:

<code class="sourceCode python"><span class="op">>>></span> <span class="cf">for</span> line <span class="op">in</span> f:
...     <span class="bu">print</span>(line, end<span class="op">=</span><span class="st">''</span>)
...
This <span class="op">is</span> the first line of the <span class="bu">file</span>.
Second line of the <span class="bu">file</span></code>

如果需要读取文件所有行到列表中,可以使用list(f)或者f.readlines()

f.write(string)将内容string写入文件,返回写入的字符串数。

<code class="sourceCode python"><span class="op">>>></span> f.write(<span class="st">'This is a test</span><span class="ch">\n</span><span class="st">'</span>)
<span class="dv">15</span></code>

其他类型的对象在写入之前对象需要转换,要么转换为字符串(文本模式),要么转换为字节对象(二进制模式):

<code class="sourceCode python"><span class="op">>>></span> value <span class="op">=</span> (<span class="st">'the answer'</span>, <span class="dv">42</span>)
<span class="op">>>></span> s <span class="op">=</span> <span class="bu">str</span>(value)  <span class="co"># convert the tuple to string</span>
<span class="op">>>></span> f.write(s)
<span class="dv">18</span></code>

在二进制模式中,f.tell()方法返回一个数字,该数字指示文件对象在文件中的当前位置,是相对于文件开始的字节数目。在文本模式中,该方法返回一个模糊的数字。

使用f.seek(offset, from_what)改变文件对象的位置。offset(偏移量)加上from_what参数指定的参考点计算出要移动到的位置。from_what值为0时表示文件开头为参考点,1表示当前文件位置为参考点,2表示文件末尾为参考点。from_what可以省略,默认为0,指示文件开头为参考点。

<code class="sourceCode python"><span class="op">>>></span> f <span class="op">=</span> <span class="bu">open</span>(<span class="st">'workfile'</span>, <span class="st">'rb+'</span>)
<span class="op">>>></span> f.write(b<span class="st">'0123456789abcdef'</span>)
<span class="dv">16</span>
<span class="op">>>></span> f.seek(<span class="dv">5</span>)      <span class="co"># Go to the 6th byte in the file</span>
<span class="dv">5</span>
<span class="op">>>></span> f.read(<span class="dv">1</span>)
b<span class="st">'5'</span>
<span class="op">>>></span> f.seek(<span class="op">-</span><span class="dv">3</span>, <span class="dv">2</span>)  <span class="co"># Go to the 3rd byte before the end</span>
<span class="dv">13</span>
<span class="op">>>></span> f.read(<span class="dv">1</span>)
b<span class="st">'d'</span></code>

文本文件中(没有使用b,以文本模式打开),只允许使用相对于文件开头的seek()方法(使用seek(0, 2)寻找文件末尾例外),并且有效的offset值(偏移量)只能是f.tell()的返回值或者0。任何其他的offset值(偏移量)都会发生未定义的行为。

文件对象有一些额外的方法,比如很少使用的isatty()truncate()。查阅库文件手册获取关于文件对象的完整信息。

7.2.2 Saving structured data with json

字符串可以很容易从文件中读取或写入到文件中。由于read()方法只返回字符串,数字需要额外转换,使用如int()的函数,输入字符串'123'返回数字值123。当希望保存更为复杂的数据类型,像嵌套列表或者字典之类的,手动解析和序列化就变得复杂了。

不需要用户不断编写和调试保存复杂数据类型到文件的代码,Python提供了流行的数据交换格式JSON(JavaScript Object Notation)。标准模块json可以接收Python数据结构,并把它们转换为字符串表示形式,这个过程称为序列化。从字符串形式重新构造数据称为反序列化。在序列化合反序列换之间,字符串形式表示的对象可以存储到文件或者数据中,或者通过网络连接发送到远程目标机器。

注解:JSON格式普遍用于现代应用程序中,用于数据交换。许多程序员已经熟悉了,是一种不错的协作选择

可以使用以下代码查看对象x的JSON字符串表示形式:

<code class="sourceCode python"><span class="op">>>></span> <span class="im">import</span> json
<span class="op">>>></span> json.dumps([<span class="dv">1</span>, <span class="st">'simple'</span>, <span class="st">'list'</span>])
<span class="co">'[1, "simple", "list"]'</span></code>

另一种dumps()方法的变种,dump(),该方法简单将对象序列化到文本文件。如果f是已经以写模式打开的文本文件对象,可以使用如下代码:

<code class="sourceCode python">json.dump(x, f)</code>

可以再次解码对象,如果f是以读模式打开的文本文件对象:

<code class="sourceCode python">x <span class="op">=</span> json.load(f)</code>

以上是可以处理列表和字典的简单序列化技术,但是要处理任意类实例需要额外的操作。json模块的参考内容包含以下解释:

参见:pickle - pickle模块

与JSON不同,pickle是一种协议,允许任意复杂Python对象序列化。就这一点论,它只能用于 Python, 而不能用于与其他语言编写的应用程序通信。默认情况下它是不安全的:如果数据由熟练的攻击者精心制作, 反序列化来自一个不受信任源的 pickle 数据可以执行任意代码。

以上是[译]The Python Tutorial#Input and Output的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn