十五年测试老手,长期负责WEB\APP 项目测试,目前主要负责团队管理工作。

Python 3 的新特性

上一篇 / 下一篇  2010-10-10 16:48:28 / 个人分类:python

009 年 2 月 02 日

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

Python 版本 3,也被称为 Python 3000 或 Py3K(仿效 Microsoft® Windows® 2000 操作系统而命名的昵称)是 Guido van Rossum 通用编程语言的最新版本。虽然新版本对该核心语言做了很多改进,但还是打破了与 2.x 版本的向后兼容性。其他一些变化则是人们期待已久的,比如:51Testing软件测试网P"j(B i k!t"XNt

  • 真正的除法 — 例如,1/2 返回的是 .5
  • long 和 int 类型被统一为一种类型,删除了后缀 L
  • TrueFalse 和 None 现在都是关键字。

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

3I8Yw2~4u4`2N[0

新的 print() 函数51Testing软件测试网&@Wl [&?7e;Ysa

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

让我们考虑这样的情况,即需要将标准输出(stdout)重定向到一个日志。如下的例子会打开文件 log.txt 以便进行追加并将对象指定给 fid。之后,利用 print>> 将一个字符串重定向给文件 fid51Testing软件测试网7F c;|K[6j

>>>fid = open("log.txt", "a")
>>>print>>fid, "log text"
51Testing软件测试网:Ybj_2vJ

另外一个例子是重定向给标准错误(sys.stderr):

7Ko:J#oS0
>>>print>>sys.stderr, "an error occurred"

g4QJm)ZH~ i d0

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

l)L ],P3kE`V0
>>>fid = open("log.txt", "a")
>>>print("log.txt", file=fid)

%N@W6D @u7Qy-W5^0

这样的代码,语法更为清晰。另一个好处是通过向 sep 关键字参数传递一个字符串就能更改分割符(separator),通过向 end 关键字参数传递另外一个字符串就能更改结束字符串。要更改分割符,可以利用:51Testing软件测试网]"zzE,F

>>>print("Foo", "Bar", sep="%")
>>>Foo%Bar
51Testing软件测试网J(h&N6v3D7t X

总地来说,新的语法为:

u%hxIf0].fj;^v x0
print([object, ...][, sep=' '][, end='endline_character_here'][, file=redirect_to_here])
51Testing软件测试网1B/iML/NFi#i0[}"[?

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

51Testing软件测试网;LDC7kQ ]&Cr&|
51Testing软件测试网 a&_ X@H*X
51Testing软件测试网I.q%u9b(|0MI

&e$i.ofT~k0
回页首

&S8^h Mh8fpW@:i051Testing软件测试网-ASG/Ws[;P

从 raw_input() 到 input()51Testing软件测试网 w#|7I E'|\5[

在 Python 版本 2.x 中,raw_input() 会从标准输入(sys.stdin)读取一个输入并返回一个字符串,且尾部的换行符从末尾移除。下面的这个例子使用 raw_input() 从命令提示符获取一个字符串,然后将值赋给 quest51Testing软件测试网T_/V9c)D@l

>>>quest = raw_input("What is your quest? ")
What is your quest? To seek the holy grail.
>>>quest
'To seek the holy grail.'

G){ M"`$Jwt0G+d!q0

与之不同,Python 2.x 中的 input() 函数需要的是一个有效的 Python 表达式,比如 3+551Testing软件测试网-@h t `K

最初,曾有人建议将 input() 和 raw_input() 从 Python 内置的名称空间一并删除,因此就需要进行导入来获得输入能力。这从方法上就不对;因为,简单键入:51Testing软件测试网p}+[5q"F-s_$r

>>>quest = input("What is your quest?")

R7b2cx?t5_0

将会变为:51Testing软件测试网|"~*t|~_s

>>>import sys
>>>print("What is your quest?")
>>>quest = sys.stdin.readline()
51Testing软件测试网3pTQ9]3x z*g

对于一个简单输入而言,这太过繁琐,并且对于一个新手,这未免太难理解。往往需要向他们讲述模块 和导入 究竟是怎么回事、字符串输出以及句点操作符又是如何工作的(如此麻烦的话,与 Java™ 语言就没什么差别了)。所以,在 Python 3 内,将 raw_input() 重命名为 input(),这样一来,无须导入也能从标准输入获得数据了。如果您需要保留版本 2.x 的 input() 功能,可以使用 eval(input()),效果基本相同。51Testing软件测试网FoVTEZO.X%V5y\i

51Testing软件测试网X*iV^6R(D
51Testing软件测试网D8d8L)bNo X:c H

7DN/K~+k O*Q;L0
51Testing软件测试网/A7fk*JBLO
回页首
51Testing软件测试网b\j W0?e

4J'Xj#H Bm'| ^0

有关 bytes 的简介51Testing软件测试网-Qe wivK3q

新的数据类型 bytes literal 及 bytes 对象的用途是存储二进制数据。此对象是 0 到 127 的不可修改的整数序列或纯粹的 ASCII 字符。实际上,它是版本 2.5 中 bytearray 对象的不可修改版本。一个 bytes literal 是一个前面冠以 b 的字符串 — 例如,b'byte literal'。对 bytes literal 的计算会生成一个新的 bytes 对象。可以用 bytes() 函数创建一个新的 bytes 对象。bytes 对象的构造函数为:

h _meo0
bytes([initializer[, encoding]])

-Sum]'mU;`0

例如:51Testing软件测试网/Kh)g"K1_%F$\

>>>b = (b'\xc3\x9f\x65\x74\x61')
>>>print(b)
b'\xc3\x83\xc2\x9feta'
51Testing软件测试网*?6rt n7_O"b

会创建一个 bytes 对象,但这是多余的,因为通过赋值一个 byte literal 就完全可以创建 bytes 对象。(我只是想要说明这么做是可行的,但是我并不建议您这么做。)如果您想要使用 iso-8859-1 编码,可以尝试下面的做法:

Y$eI3F?$f D0
>>>b = bytes('\xc3\x9f\x65\x74\x61', 'iso-8859-1')
>>>print(b)
b'\xc3\x83\xc2\x9feta'
51Testing软件测试网q3d3F3YF}pJR0U}

如果初始化器(initializer)是一个字符串,那么就必须提供一种编码。如果初始化器是一个 bytes literal,则无须指定编码类型:请记住,bytes literal 并不是字符串。但是与字符串相似,可以连接多个字节:

+s-`8PG u,u |0Y0
>>>b'hello' b' world'
b'hello world'
51Testing软件测试网;`2m{n!U]J

用 bytes() 方法代表二进制数据以及被编码的文本。要将 bytes 转变为 str, bytes 对象必须要进行解码(稍后会详细介绍)。二进制数据用 decode() 方法编码。例如:

6N"vN4N KfHG0
>>>b'\xc3\x9f\x65\x74\x61'.decode()
'ßeta'

b#KT-kM"@0PG0

也可以从文件中直接读取二进制数据。请看以下的代码:

lc2A,@ T)q N {6W0
>>>data = open('dat.txt', 'rb').read() 
>>>print(data) # data is a string
>>># content of data.txt printed out here

4_B@0\^x w0

它的功能是打开文件以便在二进制模式内读取一个文件对象,并在整个文件内进行读取。

(uJ(`1P6S0
/I%?:o4{!F&J7C0
51Testing软件测试网7Wg)r yQD,SZZ
51Testing软件测试网!psP.i!Wq `
51Testing软件测试网4w @ e t/m}P|
回页首
51Testing软件测试网q5W(IY%hZ9o%f&m
51Testing软件测试网 zG#[ h6NjJq&[

字符串

'h R&YrX6} ?Zq~S0

Python 具有单一的字符串类型 str,其功能类似于版本 2.x 的 unicode 类型。换言之,所有字符串都是 unicode 字符串。而且 — 对非拉丁文的文本用户也非常方便 — 非-ASCII 标识符现在也是允许的。例如:

5h1{M5Df+A0
>>>césar = ["author", "consultant"]
>>>print(césar)
['author', 'consultant']
51Testing软件测试网+|#C(m2maq

在 Python 之前的版本内,repr() 方法会将 8-位字符串转变为 ASCII。例如:51Testing软件测试网1D4k-\d#O$t3~4kc

>>>repr('é')
"'\\xc3\\xa9'"
51Testing软件测试网H H:o*^ U|8P P&_

现在,它会返回一个 unicode 字符串:51Testing软件测试网 ?8t(N N.n6m8w,N

>>>repr('é')
"'é'"

%e$`y G\ `$I0

正如我之前提到的,这个字符串是内置的字符串类型。

5@ D+E8C3n1V{KzOPf0

字符串对象和字节对象是不兼容的。如果想要得到字节的字符串表示,需要使用它的 decode() 方法。相反,如果想要从该字符串得到 bytes literal 表示,可以使用字符串对象的 encode() 方法。51Testing软件测试网|DS u"kU#MO

51Testing软件测试网l'k*SK \x z
51Testing软件测试网[c t Q'Z%^
51Testing软件测试网&h0U+l"Pv%]{
51Testing软件测试网"_C(B-^?$YG
回页首

#@nki-`!E3Z_0
H%q1D zL0

字符串格式化方面的变化

o W'ms3E~"HP(@0

很多 Python 程序员都感觉用来格式化字符串的这个内置的 % 操作符太有限了,这是因为:

EV4@o5D$\ ?0
  • 它是一个二进制的操作符,最多只能接受两个参数。
  • 除了格式化字符串参数,所有其他的参数都必须用一个元组(tuple)或是一个字典(dictionary)进行挤压。

这种格式化多少有些不灵活,所以 Python 3 引入了一种新的进行字符串格式化的方式(版本 3 保留了 % 操作符和 string.Template 模块)。字符串对象现在均具有一个方法 format(),此方法接受位置参数和关键字参数,二者均传递到 replacement 字段 。Replacement 字段在字符串内由花括号({})标示。replacement 字段内的元素被简单称为一个字段。以下是一个简单的例子:51Testing软件测试网e!j{0ryt;A

>>>"I love {0}, {1}, and {2}".format("eggs", "bacon", "sausage")
'I love eggs, bacon, and sausage'
51Testing软件测试网1r5Wg0Z#E(p9^

字段 {0}{1} 和 {2} 通过位置参数 eggs、 bacon 和 sausage 被传递给 format() 方法。如下的例子显示了如何使用 format() 通过关键字参数的传递来进行格式化:51Testing软件测试网e k6q6S)e2v]

>>>"I love {a}, {b}, and {c}".format(a="eggs", b="bacon", c="sausage")
'I love eggs, bacon, and sausage'
51Testing软件测试网IB F {T,z

下面是另外一个综合了位置参数和关键字参数的例子:

s8P~ Q Bwd?y0
>>>"I love {0}, {1}, and {param}".format("eggs", "bacon", param="sausage")
'I love eggs, bacon, and sausage'

4J5H"V1S)C9S-_0

请记住,在关键字参数之后放置非关键字参数是一种语法错误。要想转义花括号,只需使用双倍的花括号,如下所示:51Testing软件测试网e,h5Q,_ lWw/Q

>>>"{{0}}".format("can't see me")
'{0}'

PdTv/yXz.Y"a0

位置参数 can't see me 没有被输出,这是因为没有字段可以输出。请注意这不会产生错误。51Testing软件测试网+Z z;QB K q~

新的 format() 内置函数可以格式化单个值。比如:51Testing软件测试网2Zf[ |]%X

>>>print(format(10.0, "7.3g"))
       10
51Testing软件测试网1on5m+i \vr*Lt

换言之,g 代表的是 一般格式,它输出的是宽度固定的值。小数点前的第一个数值指定的是最小宽度,小数点后的数值指定的是精度。format specifier 的完整语法超出了本文的讨论范围,更多信息,可以参见本文的 参考资料 小节。

kl2x(N-j8d c051Testing软件测试网F H1o1b h:ZL
51Testing软件测试网lm4LG['Mje v0e

nn O|5g'@l0

8J1VpB"h~ Lxv,_0
回页首

b6E1G+ceCx(Ui#\051Testing软件测试网)|"U A|MM*w t&F

内置 dict 类型的变化

;L7W~]8z9M]G^I0

3.0 内的另一个重大改变是字典内 dict.iterkeys()、 dict.itervalues() 和 dict.iteritems() 方法的删除。取而代之的是 .keys()、 .values() 和 .items(),它们被进行了修补,可以返回轻量的、类似于集的容器对象,而不是键和值的列表。这样的好处是在不进行键和条目复制的情况下,就能在其上执行 set 操作。例如:

O$u"DuQr:kFV0
>>>d = {1:"dead", 2:"parrot"}
>>>print(d.items())
<built-in method items of dict object at 0xb7c2468c>
51Testing软件测试网7{_"s,s)hS?l

注意:在 Python 内, 是惟一元素的无序集合。51Testing软件测试网;o'e:@ t]^1K?

这里,我创建了具有两个键和值的一个字典,然后输出了 d.items() 的值,返回的是一个对象,而不是值的列表。可以像 set 对象那样测试某个元素的成员资格,比如:51Testing软件测试网ZB0p yr|,{

>>>1 in d # test for membership
True

&d Je E*m g0

如下是在 dict_values 对象的条目上进行迭代的例子:

qWaDiz0
>>>for values in d.items():
...     print(values) 
...
dead
parrot

uD JdV0

不过,如果您的确想要得到值的列表,可以对所返回的 dict 对象进行强制类型转换。比如:

q0jXsR+E$s0
>>>keys = list(d.keys())
>>>print(keys)
[1,2]
51Testing软件测试网*];M@h l,L}

hx5AR`"OYAX0
51Testing软件测试网xz5F2O"d2R@O
51Testing软件测试网~.B f;G _W
51Testing软件测试网aF(qI*B+htI
回页首
51Testing软件测试网"R+bho5Mr5})r

o z^8i*R]ukA6c0

新的 I/O51Testing软件测试网K4J#h }bB)|7RE vc6hZ

元类
6ao6Ob6m@zD0

Wikipedia 对元类的定义是这样的,“一个元类 是这样一个类,其实例也是类。” 在本系列的第 2 部分我会对这个概念进行详细的介绍。51Testing软件测试网)h'u-x_)s

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

4E X-uxN:\WYU0

ABC 是一些无法被实例化的类。要使用 ABC,子类必须继承自此 ABC 并且还要覆盖其抽象方法。如果方法的前缀使用 @abstractmethod 修饰符(decorator),那么此方法就是一个抽象方法。新的 ABC 框架还提供了 @abstractproperty 修饰符以便定义抽象属性。可以通过导入标准库模块 abc 来访问这个新框架。清单 1 所示的是一个简单的例子。51Testing软件测试网.U#d%A&X0UE:H

51Testing软件测试网 |o w9Ld zIK
清单 1. 一个简单的抽象基类
!AgQ6p%iD]-ti0
from abc import ABCMeta.
class SimpleAbstractClass(metaclass=ABCMeta):
    pass

SimpleAbstractClass.register(list)

assert isinstance([], SimpleAbstractClass)

R.q)vZ#r0

register() 方法调用接受一个类作为其参数并会让此 ABC 成为所注册类的子类。这一点可以通过在最后一行上调用 assert 语句进行验证。清单 2 是使用修饰符的另外一个例子。

/q.J}Fmc9mM)Z h0
~&f a+g*hx0清单 2. 使用修饰符的一个抽象基类
.T[mvH0
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

/M7j;s+mGJ#k|0

了解了 ABC 之后,我们就可以继续探究新的 I/O 系统了。之前的 Python 发布版都缺少一些重要但是出色的函数,比如用于类似于流的对象的 seek()。 类似于流的对象 是一些具有 read() 和 write() 方法的类似于文件的对象 — 比如,socket 或文件。Python 3 具有很多针对类似于流的对象的 I/O 层 — 一个原始的 I/O 层、一个被缓冲的 I/O 层以及一个文本 I/O 层 — 每层均由其自身的 ABC 及实现定义。

/} r amK5N9\A2r0

打开一个流还是需要使用内置的 open(fileName) 函数,但是也可以调用 io.open(fileName))。这么做会返回一个缓冲了的文本文件;read() 和 readline() 会返回字符串(请注意,Python 3 内的所有字符串都是 unicode)。您也可以使用 open(fileName, 'b') 打开一个缓冲了的二进制文件。在这种情况下,read() 会返回字节,但 readline() 则不能用。

)wmF k!q-G0

此内置 open() 函数的构造函数是:51Testing软件测试网 f)[g6enjS

open(file,mode="r",buffering=None,encoding=None,errors=None,newline=None,closefd=True)
51Testing软件测试网5U8R-|? lv$K$io

可能的模式有:

awW#W9T&v/U$r IFz0
  • r
  • w打开供写入
  • a打开供追加
  • b二进制模式
  • t文本模式
  • +打开一个磁盘文件供更新
  • U通用换行模式

默认的模式是 rt,即打开供读取的文本模式。

*P6ICz&j0?0

buffering 关键字参数的期望值是以下三个整数中的一个以决定缓冲策略:51Testing软件测试网|/Q4c bw

  • 0关闭缓冲
  • 1行缓冲
  • > 1完全缓冲(默认)

默认的编码方式独立于平台。关闭文件描述符或 closefd 可以是 True 或 False。如果是 False,此文件描述符会在文件关闭后保留。若文件名无法奏效的话,那么 closefd 必须设为 True。51Testing软件测试网fr |IC }

open() 返回的对象取决于您所设置的模式。表 1 给出了返回类型。51Testing软件测试网$M-dj O#e&wBaV

51Testing软件测试网i.rI$I!u)}
表 1. 针对不同打开模式的返回类型51Testing软件测试网Sv9^[#KOm
模式返回对象
文本模式TextIOWrapper
二进制BufferedReader
写二进制BufferedWriter
追加二进制BufferedWriter
读/写模式BufferedRandom

请注意:文本模式可以是 w、 rwt、 rt 等。

:m'FK(R-}0?0

清单 3 中所示的例子打开的是一个缓冲了的二进制流以供读取。51Testing软件测试网X2_^V0J nV'D!fC


1^ B&HTM GZ0清单 3. 打开一个缓冲了的二进制流以供读取
pb Od6Om/L|{p0
>>>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

8Up n|5`2Dg0

BufferedReader 对象可以访问很多有用的方法,比如 isatty、 peekraw、 readintoreadline、 readlinesseek、 seekabletell、 writablewrite 和 writelines。要想查看完整列表,可以在 BufferedReader 对象上运行 dir()51Testing软件测试网b:`"H E6G0e5Uw


&i T*i9{F{G0

/cei;rNvz$^S/l/a0

:Y!tL]+K0
51Testing软件测试网U[k4k2Gx-^/Z,?
回页首

BjDY$_/I9V K0
c {$Ed.H U}Y|D4r/t0

结束语51Testing软件测试网,{+j+XV;g5gz*C,F

Python 社区是否会接??版本 3 还尚在人们的猜测之中。打破向后兼容性意味着将要为两种版本提供支持。一些项目开发人员可能不太想迁移其项目,即便是使用版本 2 到 3 的转化器。就我个人而言,我发现从 Python 版本 2 迁移到 3 其实不过是对几个事情的重新认识:它当然不会像从 Python 迁移到 Java 或 Perl 语言那样变化强烈。很多变化是早就在人们意料中的,比如对 dict 的实质更改。执行 print() 远比执行 Java 的 System.out.println() 容易得多,学习起来也相对容易,所以的确能带来一些好处。

SD F5^$zl)B A!X{2i0

我猜想,blogosphere 内的一些帖子会让 Python 的支持者也会误认为其中的某些变更 — 例如对向后兼容性的打破 — 具有破坏性的影响。 Lambda 本来就是准备好要删除的,只不过一直没有这么做,仍保留了其原始的格式。有关保留项目的完整列表,请访问 Python 核心开发站点。如果您具备足够的探索精神愿意深入研究所有的 PEP,那么您一定能够从中获得更深入的信息。51Testing软件测试网u vo(H1OPA^

本系列的下一期文章将会涵盖更高级的主题,比如元类语法、ABC、修饰符、integer literal 支持、基类型和异常。51Testing软件测试网%L6y+Ehpodw(o

51Testing软件测试网p_N9cS*t$K
51Testing软件测试网o.}.P$I8l2o-H!F!J

参考资料51Testing软件测试网Y/FIM5\F.Ft {]

学习
S2jh3Cbr8]qVS.O0
  • 您可以参阅本文在 developerWorks 全球网站上的 英文原文51Testing软件测试网t7Z hr&s6xw

    #MyYj g5Hz0
  • 有关 format specifier 的完整语法,请访问 Python 核心开发站点。 
    +x|${1p^aG(~z-Z0
    J8|NS"tj0E0
  • 阅读相关的 Python 3 PEP:
    • PEP 3111:Simple input built-in in Python 3000
    • PEP 3116:New I/O
    • PEP 3138:String representation in Python 3000
    • PEP 3112:Bytes literals in Python 3000
    • PEP 3137:Immutable Bytes and Mutable Buffer
    • PEP 3106:Revamping dict.keys(), .values() & .items()
    • PEP 3108:Standard Library Reorganization
    • PEP 3100:Miscellaneous Python 3.0 Plans
    51Testing软件测试网 c%])yq@d+\ D
  • 请参阅 Wikipedia 上的 元类。 51Testing软件测试网#k/nHweB;c9^
    51Testing软件测试网PKR&`P(I k%L3_
  • 查阅计算机课程,包括 Wikipedia 上的 抽象类。 
    #\7[7K5}?Q9R3V7D.o0
    SdZU?r!L ^$o0
  • 阅读 Guido van Rossum 的论文。 51Testing软件测试网4{${tQ.k
    51Testing软件测试网 ["ar,p Ej4t CU|
  • 了解 Python 的 惟一元素的无序集合 或。 
    G7~Altp$t^:|Di051Testing软件测试网"Gw$@BD3O;r'C
  • 在 developerWorks Linux 专区 寻找为 Linux 开发人员(包括 Linux 新手入门)准备的更多参考资料,查阅我们 最受欢迎的文章和教程。 51Testing软件测试网(h[N,v x6_

    ~@#X^chX0
  • 在 developerWorks 上查阅所有 Linux 技巧 和 Linux 教程。 51Testing软件测试网VS _a0d'k1AYU
    51Testing软件测试网-fJ Jb*m
  • 随时关注 developerWorks 技术活动和网络广播。 
    "[ N*q4r4G+aw0
    4u$WO2{B c h0

pD'u]jz0获得产品和技术51Testing软件测试网%K2HtuI C*L%{
  • 获得 Python 的最新版本。 
    #VC,~*\0y/M2X051Testing软件测试网\jd@V!l1s[|
  • 利用可直接从 developerWorks 下载的 IBM 试用软件 构建您的下一个 Linux 开发项目。 51Testing软件测试网aB"YS,Rj

    9X2mW)J&S-s)]:w,_ Ee0
51Testing软件测试网/lz}_d({%R2]u-nC
讨论
(dPD]2l)u0
6AG/|*c Qwq0
Z6Hd$R[%V[[X0


TAG: Python python

 

评分:0

我来说两句

Open Toolbar