Python3的变化

这里我们将对Python 3.1核心语言的变化进行分析,包括字符串的格式化、说明符以及其他方面的内容。希望这些变化能对大家了解Python 3.1有所帮助。

Python 3.0发布七个月之后,Python核心开发人员于2009年6月27日发布了新的Python 3.1版本。虽然此3.1版本只是对Python 3.0的一次小型升级,但是它不仅为开发者带来许多让人感兴趣的特性,同时在性能方面也有所改善。本文将为读者详细介绍Python 3.1版本在核心语言、标准程序库和性能改善方面的变化。

一、字符串的格式化

Python的最新版本为我们带来了讨人喜欢的格式字段的自动填数功能。我们知道,许多程序中经常需要格式化字符串。Python 2.x版本使用的是类似[s]printf函数的百分号操作符,如下所示:

 
 
  1. >>> '%s, %s!' % ('Hello', 'World') 

'Hello, World!'而Python 3.0则添加了更高级的字符串格式化功能,如下所示:

 
 
  1. >>> '{0}, {1}!'.format('Hello''World'

'Hello, World!'如今,Python 3.1则在字符串格式化方面又有了新的改进。对于Python 3.0来说,每当您想在格式串中引用位置参数时,您必须给出每个位置参数的索引。但是在Python 3.1中,您就可以将这些索引抛在脑后了,因为Python会依次替您填充这些参数:

 
 
  1. >>> '{}, {}!'.format('Hello''World')  
  2. 'Hello, World!' 

二、PEP-378:用于千位分隔符的格式说明符

在财务应用程序中,通常要在数字中使用千位分隔符。从事金融或者财会方面工作的人士是不这样写的“您欠我$12345678”,而是“您欠我$12,345,678”,他们惯于使用逗号作为分隔符。那么,如何使用Python达到这种效果呢:

 
 
  1. >>> format(12345678','

'12,345,678'您可以利用其他区分符对数字进行分组。这里的宽度说明符(这里为8)包括了逗号和小数点:

 
 
  1. >>> format(1234',').replace(',''_'

'12,345.7'逗号通常作为默认的分隔字符,如果要使用其他字符作为分隔字符的话,只需通过replace函数用您喜欢的字符替换逗号即可,具体如下所示:

 
 
  1. >>> format(1234',').replace(',''_'

'1_234'当然,您还可以使用format函数来作为字符串方法:
>>> '{0:8,.1f}'.format(123.456)

三、Maketrans函数

利用maketrans()和translate()函数,我们可以使用一组字符来替换另一组字符。使用这一替换功能时,多少有点繁琐,因为它要求使用maketrans()函数(该函数的作用是把输入字符映射到输出字符)建立一个转换表,然后,再把这个转换表传递给translate()函数。当然,string模块仍然有它自己的maketrans()函数,不过Python 3.1不赞成使用它,而是赞赏使用单独的maketrans()函数来操作字节、字节数组和字符串。

下面的例子演示了如何使用maketrans()和translate()函数处理字节对象。需要注意的是,用于字节的转换表具有256个表项(每一项对应于一个可能的字节),并且这个例子把大部分字节都映射到它们自身,只有1,2和3例外,因为它们分别映射到了4,5和6。如下所示:

 
 
  1. >>> tt = bytes.maketrans(b'123', b'456')  
  2. >>> len(tt)  
  3. 256 
  4. >>> tt  
  5. b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\  
  6. t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\  
  7. x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\  
  8. x1e\x1f !"#$%&\'()*+,-./0456456789:;<=>  
  9. ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcd  
  10. efghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\  
  11. x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\  
  12. x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\  
  13. x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\  
  14. xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\  
  15. xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\  
  16. xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\  
  17. xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\  
  18. xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\  
  19. xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\  
  20. xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\  
  21. xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\  
  22. xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\  
  23. xfa\xfb\xfc\xfd\xfe\xff' 

建好转换表之后,我们只需把它传递给translate()函数即可,如下所示:

 
 
  1. >>> b'123456'.translate(tt) 

b'456456'我们还可以传递其它的参数作为要删除的字符:

 
 
  1. >>> b'123456'.translate(tt, b'5'

b'45646'我们可以看到,原来的5已经从123456从删掉了,但是转换得到的5(请记住,我们的映射表将2转化为5)并没有删除。这说明,系统是先从原来的字符串中删除相应的字符,然后才进行的转换操作。
字符串的转换稍微有些不同,字符串版本的maketrans函数返回的是一个字典:

 
 
  1. >>> tt = str.maketrans('123''456')  
  2. {495250535154}  
  3. >>> '123456'.translate(tt)  
  4. '456456' 

四、与数学有关的变化

 
 
  1. >>> int.bit_length(19)  
  2. 5 
  3. >>> bin(19

3.1版本在与数学有关的方面也有所改变。

Int添加了一个bit_length方法

新版本中,int变量具有一个bit_length方法,它能返回该int变量以二进制数表示的时候的位数。例如,数字19的二进制表示为10011,那么它的位数就是5:

'0b10011'浮点数的舍入

在Python 3.0以及早先的round()函数有点反复无常:如果您不指定精度的时候,它返回的是一个整数;如果指定精度的话,它返回的是您输入数据的类型:

 
 
  1. >>> round(1000)  
  2. 1000 
  3. >>> round(1000.0)  
  4. 1000 
  5. >>> round(10002)  
  6. 1000 
  7. >>> round(1000.02)  

1000.0在Python 3.1中,只要输入的数字是一个整数(即使它是用浮点数的形式表示的,例如1000.0),那么它总是返回一个整型数:

 
 
  1. >>> round(1000)  
  2. 1000 
  3. >>> round(1000.0)  
  4. 1000 
  5. >>> round(10002)  
  6. 1000 
  7. >>> round(1000.02

1000浮点数的表示

目前,实数在大部分的硬件和操作系统中都是用32位(单精度)或者64位(双精度)来表示的。然而,这会导致一些实数无法精确表示。由于计算机存储器的二进制特性,某些数字利用十进制表示形式非常简洁,但是要是使用浮点方案表示的话,就要复杂了。举例来说,利用32位的单精度浮点数表示数字0.6,则为0.59999999999999998:

>>> 0.6

0.59999999999999998对于这种表示方案,上面的数字是为了做到尽可能的精确,但是对用户来说却很不友好。 Python 3.1使用了一个新算法,以便使得原值的表示尽可能得简练。所以在Python 3.1中,人们输入上面的数字,一个更简洁的表示:

>>> 0.6

0.6这已经很精确了,除非遇到算术运算。举例来说,表达式0.7+0.1的值用32位浮点表示法表示的话,它是 0.79999999999999993,而数字0.8的值用32位浮点数表示则是 0.80000000000000004。 这样一来,就意味着0.7+0.1并不等于0.8,这会导致一些问题。例如,下面的循环将永不休止:

 
 
  1. >>> x = 0.0 
  2. >>> while x != 1.0:  
  3. ... print(repr(x))  
  4. ... x += 0.1输出的结果:  
  5. 0 
  6. 0.10000000000000001 
  7. 0.20000000000000001 
  8. 0.30000000000000004 
  9. 0.40000000000000002 
  10. 0.5 
  11. 0.59999999999999998 
  12. 0.69999999999999996 
  13. 0.79999999999999993 
  14. 0.89999999999999991 
  15. 0.99999999999999989 
  16. 1.0999999999999999 
  17. 1.2 
  18. 1.3 
  19. 1.4000000000000001 
  20. 1.5000000000000002 
  21. 1.6000000000000003 

...在Python 3.0中,repr()函数返回的是实际表示;而在Python 3.1中,它返回的是简洁表示。无论是在Python 3.0还是在Python 3.1中,print()函数显示的都是简洁表示:

 
 
  1. >>> print(0.1)  
  2. 0.1  
  3. >>> print(0.10000000000000001) 

0.1Python语言还有一个称为decimal的模块,可用于精确的实数表示。它使用一个不同的表示方案来表示浮点数,并且在内存运行的情况下,用尽量多的数位来表示一个实数——并且,当进行算术的时候不会出现舍入误差。在Python 3.0中,Decimal类型使用了一种新方法来从一个字符串初始化它表示的值;在Python 3.1中,又增加了另一个新方法即from_float()来接收浮点数。注意,即使当使用from_float()的时候,Decimal模块也会比32位更精确。

 
 
  1. >>> from decimal import Decimal  
  2. >>> Decimal.from_float(0.1)  
  3. Decimal('0.1000000000000000055511151231257827021181583404541015625')  

五、改进的WITH语句

在Python 2.5中,WITH语句是作为一个__future__特性引入的,该语句的正式引入实际上是从Python 3.0开始的。到了Python 3.1版本,该语句已经能够支持更多的资源。最常见的情形是,它可以打开输入、输出文件并在处理完成后关闭它们。在Python 3.0中,我们要么使用嵌套的with语句,要么显式闭合在文件中。下面是一个Python 3.0的例子,它打开了一个输入文件,将其内容作为字符串读取,用字符串的title()方法处理内容,并将结果写到一个输出文件中。
这个示例中含有两个嵌套的with语句,注意嵌套的with语句中的最后一行。当代码试图读取out.txt的时候,结果为空,因为此文件是被缓冲处理的,并且还没有写入。当此with语句完成的时候,Python会关闭此文件,所以最后一行代码会认定out.txt的内容的确是大写文字。

 
 
  1. open('in.txt''w').write('abc def')  
  2. with open('in.txt') as in_file:  
  3. with open('out.txt''w') as out_file:  
  4. text = in_file.read()  
  5. assert text == 'abc def' 
  6. text = text.title()  
  7. assert text == 'Abc Def' 
  8. out_file.write(text)  
  9. assert open('out.txt').read() == '' 

assert open('out.txt').read() == 'Abc Def'看到嵌套的with语句,是不是感觉有点头疼,呵呵。接下来,我们要打开两个两个文件,并在处理完成后关闭它们(如果您需要打开三个文件,那么就需要三个嵌套的with语句)。 Python 3.1运行您使用单个WITH语句打开所有文件:

 
 
  1. open('in.txt''w').write('abc def')  
  2. with open('in.txt') as in_file:  
  3. with open('out.txt''w') as out_file:  
  4. text = in_file.read()  
  5. assert text == 'abc def' 
  6. text = text.title()  
  7. assert text == 'Abc Def' 
  8. out_file.write(text)  
  9. assert open('out.txt').read() == '' 
  10. assert open('out.txt').read() == 'Abc Def' 

Python 3.1的另一项改进就是,gzip.GzipFile和bz2.BZ2File现在也能用于WITH语句。我们知道,这些都是压缩后的文件格式。下面的示例代码将使用gzip文件和bz2文件来存储5000个字节的内容,并显示其尺寸。这里还有用到一些额外的Python 3特性,比如带有命名属性的统计结果和高级字符串格式化。

 
 
  1. from bz2 import BZ2File  
  2. from gzip import GzipFile  
  3. import os  
  4. with GzipFile('1.gz''wb') as g, BZ2File('1.bz2''wb') as b:  
  5. g.write(b'X' * 5000)  
  6. b.write(b'X' * 5000)  
  7. for ext in ('.gz''.bz2'):  
  8. filename = '1' + ext  
  9. print ('The size of the {0} file is {1.st_size} bytes'.format(ext, os.stat(filename)))输出的结果:  
  10. The size of the .gz file is 43 bytes  
  11. The size of the .bz2 file is 45 bytes 

六、小结

Python 3.0发布七个月之后,Python核心开发人员于2009年6月27日发布了新的Python 3.1版本。虽然此3.1版本只是对Python 3.0的一次小型升级,但是它不仅为开发者带来许多让人感兴趣的特性,同时在性能方面也有所改善。本文为读者详细介绍了Python 3.1版本在核心语言方面的变化,在接下来的文章中,我们将继续为读者介绍新版本中标准程序库和性能改善方面的变化。



-----------------------------------------------------------------------------------------------


Python3的变化

摘要(commend)

  1. print 由一个语句(statement)变为一个函数
  2. Python3中的 str 类型现在是原来的 unicode 类型,而原 str 类型现在是 bytes
  3. 由第 2 条,uincode() 函数被移除,功能由 str()取代,而原 str() 由 bytes() 取代
  4. 长整型(long)和整型(int)统一为整形(int)
  5. 不再支持 <> 比较运算符号,仅支持 !=
  6. 字典(dict)对象的 has_key() 方法被移除,仅支持 in 操作
  7. 许多字典(dict)类方法返回值是列表的变为动态视图(dynamic view),视图(view)不支持索引操作
  8. 几个相关的 HTTP 模块被组合为一个单独的包,即 http
  9. 包内的相对导入
  10. 定义新的全局函数 next() ,它使用一个迭代器作为参数
  11. filter() 函数返回一个迭代器(iterator)而不是列表(list)
  12. map() 函数返回一个迭代器(iterator)而不是列表(list)
  13. reduce() 不再是全局函数,它现在被放在 functools 模块里
  14. apply() 函数被移除
  15. intern() 不再是全局函数,它现在被放在 sys 模块里
  16. exec 由一个语句变为一个函数




-----------------------------------------------------------------------------------------------





2009 年 2 月 02 日
Python 3 是 Guido van Rossum 功能强大的通用编程语言的最新版本。它虽然打破了与 2.x 版本的向后兼容性,但却清理了某些语法方面的问题。本文是系列文章中的第一篇,介绍了影响该语言及向后兼容性的各种变化,并且还提供了新特性的几个例子。

Python 版本 3,也被称为 Python 3000 或 Py3K(仿效 Microsoft® Windows® 2000 操作系统而命名的昵称)是 Guido van Rossum 通用编程语言的最新版本。虽然新版本对该核心语言做了很多改进,但还是打破了与 2.x 版本的向后兼容性。其他一些变化则是人们期待已久的,比如:
真正的除法 — 例如,1/2 返回的是 .5。
long 和 int 类型被统一为一种类型,删除了后缀 L。
True、False 和 None 现在都是关键字。

本文 — Python 3 系列文章中的第一篇 — 的内容涵盖了新的 print() 函数、input()、输入/输出(I/O)的变化、新的 bytes 数据类型、字符串和字符串格式化的变化以及内置的 dict 类型的变化。本文面向的是那些熟悉 Python 并对新版本的变化很感兴趣但又不想费力读完所有 Python Enhancement Proposal(PEP)的编程人员。(本文后面的 参考资料 部分提供了有关这些 PEP 的链接。)

新的 print() 函数

如今,您将需要让手指习惯于键入 print("hello"),而不是原来的 print "hello",这是因为 print 现在是一个函数,不再是一个语句。我知道,这多少有点痛苦。我认识的每个 Python 程序员 — 一旦安装了版本 3 并得到 “语法不正确” 错误 — 都会郁闷地大叫。我知道这两个额外的符号十分讨厌;我也知道这将会破坏向后兼容性。但是这种改变还是有好处的。

让我们考虑这样的情况,即需要将标准输出(stdout)重定向到一个日志。如下的例子会打开文件 log.txt 以便进行追加并将对象指定给 fid。之后,利用 print>> 将一个字符串重定向给文件 fid:>>>fid = open("log.txt", "a")
>>>print>>fid, "log text"



另外一个例子是重定向给标准错误(sys.stderr):>>>print>>sys.stderr, "an error occurred"



上述两个例子都不错,但还有更好的解决方案。新的语法只要求给 print() 函数的关键字参数 file 传递一个值就可以了。比如:>>>fid = open("log.txt", "a")
>>>print("log.txt", file=fid)



这样的代码,语法更为清晰。另一个好处是通过向 sep 关键字参数传递一个字符串就能更改分割符(separator),通过向 end 关键字参数传递另外一个字符串就能更改结束字符串。要更改分割符,可以利用:>>>print("Foo", "Bar", sep="%")
>>>Foo%Bar



总地来说,新的语法为:print([object, ...][, sep=' '][, end='endline_character_here'][, file=redirect_to_here])



其中,方括号([])内的代码是可选的。默认地,若只调用 print() 自身,结果会追加一个换行符( \n)。


回页首





从 raw_input() 到 input()

在 Python 版本 2.x 中,raw_input() 会从标准输入(sys.stdin)读取一个输入并返回一个字符串,且尾部的换行符从末尾移除。下面的这个例子使用 raw_input() 从命令提示符获取一个字符串,然后将值赋给 quest。>>>quest = raw_input("What is your quest? ")
What is your quest? To seek the holy grail.
>>>quest
'To seek the holy grail.'



与之不同,Python 2.x 中的 input() 函数需要的是一个有效的 Python 表达式,比如 3+5。

最初,曾有人建议将 input() 和 raw_input() 从 Python 内置的名称空间一并删除,因此就需要进行导入来获得输入能力。这从方法上就不对;因为,简单键入:>>>quest = input("What is your quest?")



将会变为:>>>import sys
>>>print("What is your quest?")
>>>quest = sys.stdin.readline()



对于一个简单输入而言,这太过繁琐,并且对于一个新手,这未免太难理解。往往需要向他们讲述模块 和导入 究竟是怎么回事、字符串输出以及句点操作符又是如何工作的(如此麻烦的话,与 Java™ 语言就没什么差别了)。所以,在 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'。对 bytes literal 的计算会生成一个新的 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())
<built-in method items of dict object at 0xb7c2468c>



注意:在 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 元类

Wikipedia 对元类的定义是这样的,“一个元类 是这样一个类,其实例也是类。” 在本系列的第 2 部分我会对这个概念进行详细的介绍。



在深入研究 I/O 的新机制之前,很有必要先来看看抽象基类( abstract base classes,ABC)。更深入的介绍将会在本系列的第 2 部分提供。 

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 
<io.BufferedReader object at 0xb7c2534c>
>>>f.close()                         # close stream



BufferedReader 对象可以访问很多有用的方法,比如 isatty、 peek、raw、 readinto、readline、 readlines、seek、 seekable、tell、 writable、write 和 writelines。要想查看完整列表,可以在 BufferedReader 对象上运行 dir()。













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值