print() 函数
如今,您将需要让手指习惯于键入 print(“hello”),而不是原来的 print “hello”,这是因为print 现在是一个函数,不再是一个语句让我们考虑这样的情况,即需要将标准输出(stdout)重定向到一个日志。
新的语法只要求给 print() 函数的关键字参数 file 传递一个值就可以了,比如:
fid = open(“log.txt”, “a”)
print(“log.txt”, file=fid)
这样的代码,语法更为清晰。另一个好处是通过向 sep 关键字参数传递一个字符串就能更改分割符(separator),通过向 end 关键字参数传递另外一个字符串就能更改结束字符串。要更改分割符,可以利用:
print(“Foo”, “Bar”, sep=”%”)
总地来说,新的语法为:
print([object, ...][, sep=' '][, end='endline_character_here'][,
file=redirect_to_here])
其中,方括号([])内的代码是可选的。默认地,若只调用 print() 自身,结果会追加一个换行符(\n)。
raw_input() 到 input()
在 Python 版本 2.x 中,raw_input() 会从标准输入(sys.stdin)读取一个输入并返回一个字符串,且尾部的换行符从末尾移除。在Python 2.x 版本 2.x 中, input() 函数需要的是一个有效的 Python 表达式。在 Python 3 内,将raw_input() 重命名为 input(),这样一来,无须导入也能从标准输入获得数
据了。如果您需要保留版本 2.x 的 input() 功能,可以使用 eval(input()),效果基本相同。
bytes
新的数据类型 bytes literal 及 bytes 对象的用途是存储二进制数据。此对象是 0 到 127 的不可修改的整数序列或纯粹的 ASCII 字符。实际上,它是版本 2.5 中 bytearray 对象的不可修改版本。一个 bytes literal 是一个前面冠以 b 的字符串 — 例如,b’byte literal’。对 bytesliteral 的计算会生成一个新的 bytes 对象。可以用 bytes() 函数创建一个新的 bytes 对象。
bytes 对象的构造函数为:bytes([initializer[, encoding]])
例如:
>>>b = (b’\xc3\x9f\x65\x74\x61′)
>>>print(b)
b’\xc3\x83\xc2\x9feta’
会创建一个 bytes 对象,但这是多余的,因为通过赋值一个 byte literal 就完全可以创建 bytes 对象。(我只是想要说明这么做是可行的,但是我并不建议您这么做。)如果您想要使用 iso-8859-1 编码,可以尝试下面的做法:
>>>b = bytes(‘\xc3\x9f\x65\x74\x61′, ‘iso-8859-1′)
>>>print(b)
b’\xc3\x83\xc2\x9feta’
如果初始化器(initializer)是一个字符串,那么就必须提供一种编码。如果初始化器是一个 bytes literal,则无须指定编码类型:请记住,bytes literal 并不是字符串。但是与字符串相似,可以连接多个字节:
>>>b’hello’ b’ world’
b’hello world’
用 bytes() 方法代表二进制数据以及被编码的文本。要将 bytes 转变为 str, bytes 对象必须要进行解码(稍后会详细介绍)。二进制数据用 decode() 方法编码。例如:
>>>b’\xc3\x9f\x65\x74\x61′.decode()
‘ßeta’
也可以从文件中直接读取二进制数据。请看以下的代码:
>>>data = open(‘dat.txt’, ‘rb’).read()
>>>print(data) # data is a string
>>># content of data.txt printed out here
它的功能是打开文件以便在二进制模式内读取一个文件对象,并在整个文件内进行读取。
字符串
Python 具有单一的字符串类型 str,其功能类似于版本 2.x 的 unicode 类型。换言之,所有字符串都是 unicode 字符串。而且 — 对非拉丁文的文本用户也非常方便 — 非-ASCII 标识符现在也是允许的。例如:
>>>césar = ["author", "consultant"]
>>>print(césar)
['author', 'consultant']
在 Python 之前的版本内,repr() 方法会将 8-位字符串转变为 ASCII。例如:
>>>repr(‘é’)
“‘\\xc3\\xa9′”
现在,它会返回一个 unicode 字符串:
>>>repr(‘é’)
“‘é’”
正如我之前提到的,这个字符串是内置的字符串类型。
字符串对象和字节对象是不兼容的。如果想要得到字节的字符串表示,需要使用它的 decode() 方法。相反,如果想要从该字符串得到 bytes literal 表示,可以使用字符串对象的 encode() 方法。
字符串格式化方面的变化
很多 Python 程序员都感觉用来格式化字符串的这个内置的 % 操作符太有限了,这是因为:
•它是一个二进制的操作符,最多只能接受两个参数。
•除了格式化字符串参数,所有其他的参数都必须用一个元组(tuple)或是一个字典(dictionary)进行挤压。
这种格式化多少有些不灵活,所以 Python 3 引入了一种新的进行字符串格式化的方式(版本 3 保留了 % 操作符和 string.Template模块)。字符串对象现在均具有一个方法 format(),此方法接受位置参数和关键字参数,二者均传递到 replacement 字段 。Replacement 字段在字符串内由花括号({})标示。replacement 字段内的元素被简单称为一个字段。以下是一个简单的例子:
>>>”I love {0}, {1}, and {2}”.format(“eggs”, “bacon”, “sausage”)
‘I love eggs, bacon, and sausage’
字段 {0}、{1} 和 {2} 通过位置参数 eggs、 bacon 和 sausage 被传递给 format() 方法。如下的例子显示了如何使用 format() 通过关键字参数的传递来进行格式化:
>>>”I love {a}, {b}, and {c}”.format(a=”eggs”, b=”bacon”, c=”sausage”)
‘I love eggs, bacon, and sausage’
下面是另外一个综合了位置参数和关键字参数的例子:
>>>”I love {0}, {1}, and {param}”.format(“eggs”, “bacon”, param=”sausage”)
‘I love eggs, bacon, and sausage’
请记住,在关键字参数之后放置非关键字参数是一种语法错误。要想转义花括号,只需使用双倍的花括号,如下所示:
>>>”{{0}}”.format(“can’t see me”)
‘{0}’
位置参数 can’t see me 没有被输出,这是因为没有字段可以输出。请注意这不会产生错误。
新的 format() 内置函数可以格式化单个值。比如:
>>>print(format(10.0, “7.3g”))
10
换言之,g 代表的是 一般格式,它输出的是宽度固定的值。小数点前的第一个数值指定的是最小宽度,小数点后的数值指定的是精度。format specifier 的完整语法超出了本文的讨论范围,更多信息,可以参见本文的 参考资料 小节。
内置 dict 类型的变化
3.0 内的另一个重大改变是字典内 dict.iterkeys()、 dict.itervalues() 和 dict.iteritems() 方法的删除。取而代之的是.keys()、 .values() 和 .items(),它们被进行了修补,可以返回轻量的、类似于集的容器对象,而不是键和值的列表。这样的好处是在不进行键和条目复制的情况下,就能在其上执行 set 操作。例如:
>>>d = {1:”dead”, 2:”parrot”}
>>>print(d.items())
注意:在 Python 内,集 是惟一元素的无序集合。
这里,我创建了具有两个键和值的一个字典,然后输出了 d.items() 的值,返回的是一个对象,而不是值的列表。可以像 set 对象那样测试某个元素的成员资格,比如:
>>>1 in d # test for membership
True
如下是在 dict_values 对象的条目上进行迭代的例子:
>>>for values in d.items():
… print(values)
…
dead
parrot
不过,如果您的确想要得到值的列表,可以对所返回的 dict 对象进行强制类型转换。比如:
>>>keys = list(d.keys())
>>>print(keys)
[1,2]
新的 I/O
ABC 是一些无法被实例化的类。要使用 ABC,子类必须继承自此 ABC 并且还要覆盖其抽象方法。如果方法的前缀使用 @abstractmethod 修饰符(decorator),那么此方法就是一个抽象方法。新的 ABC 框架还提供了 @abstractproperty 修饰符以便定义抽象属性。可以通过导入标准库模块 abc 来访问这个新框架。清单 1 所示的是一个简单的例子。
清单 1. 一个简单的抽象基类
from abc import ABCMeta
class SimpleAbstractClass(metaclass=ABCMeta):
pass
SimpleAbstractClass.register(list)
assert isinstance([], SimpleAbstractClass)
register() 方法调用接受一个类作为其参数并会让此 ABC 成为所注册类的子类。这一点可以通过在最后一行上调用 assert 语句进行验证。清单 2 是使用修饰符的另外一个例子。
清单 2. 使用修饰符的一个抽象基类
from abc import ABCMeta, abstractmethod
class abstract(metaclass=ABCMeta):
@abstractmethod
def absMeth(self):
pass
class A(abstract):
# must implement abstract method
def absMeth(self):
return 0
了解了 ABC 之后,我们就可以继续探究新的 I/O 系统了。之前的 Python 发布版都缺少一些重要但是出色的函数,比如用于类似于流的对象的 seek()。 类似于流的对象 是一些具有 read() 和 write() 方法的类似于文件的对象 — 比如,socket 或文件。Python 3 具有很多针对类似于流的对象的 I/O 层 — 一个原始的 I/O 层、一个被缓冲的 I/O 层以及一个文本 I/O 层 — 每层均由其自身的 ABC 及实现定义。
打开一个流还是需要使用内置的 open(fileName) 函数,但是也可以调用 io.open(fileName))。这么做会返回一个缓冲了的文本文件;read() 和 readline() 会返回字符串(请注意,Python 3 内的所有字符串都是 unicode)。您也可以使用 open(fileName, ‘b’)打开一个缓冲了的二进制文件。在这种情况下,read() 会返回字节,但 readline() 则不能用。
此内置 open() 函数的构造函数是:
open(file,mode=”r”,buffering=None,encoding=None,errors=None,newline=None,closefd=True)
可能的模式有:
•r:读
•w:打开供写入
•a:打开供追加
•b:二进制模式
•t:文本模式
•+:打开一个磁盘文件供更新
•U:通用换行模式
默认的模式是 rt,即打开供读取的文本模式。
buffering 关键字参数的期望值是以下三个整数中的一个以决定缓冲策略:
•0:关闭缓冲
•1:行缓冲
•> 1:完全缓冲(默认)
默认的编码方式独立于平台。关闭文件描述符或 closefd 可以是 True 或 False。如果是 False,此文件描述符会在文件关闭后保留。若文件名无法奏效的话,那么 closefd 必须设为 True。
open() 返回的对象取决于您所设置的模式。表 1 给出了返回类型。
表 1. 针对不同打开模式的返回类型
模式 返回对象
文本模式 TextIOWrapper
二进制 BufferedReader
写二进制 BufferedWriter
追加二进制 BufferedWriter
读/写模式 BufferedRandom
请注意:文本模式可以是 w、 r、wt、 rt 等。
清单 3 中所示的例子打开的是一个缓冲了的二进制流以供读取。
清单 3. 打开一个缓冲了的二进制流以供读取
>>>import io
>>>f = io.open(“hashlib.pyo”, “rb”) # open for reading in binary mode
>>>f # f is a BufferedReader object
>>>f.close() # close stream
BufferedReader 对象可以访问很多有用的方法,比如 isatty、 peek、raw、 readinto、readline、 readlines、seek、seekable、tell、 writable、write 和 writelines。要想查看完整列表,可以在 BufferedReader 对象上运行 dir()。