1、Python 函数
当你需要一个函数的时候,就像这样声明它就行:
函数声明以关键字 def 开头,紧跟着函数的名称,然后是用括号括起来的参数。多个参数以逗号分割。<pre name="code" class="python"><span style="font-family:Microsoft YaHei;color:#006600;">def approximate_size(size, a_kilobyte_is_1024_bytes=True):</span>
同时注意,函数不定义一个返回数据类型。 Python 函数不指定它们的返回值的类型,甚至不指定它们是否返回一个值。(事实上,每个 Python 函数都返回一个值,如果这个函数曾经执行了 return 语句,它将返回那个值,否则它将返回 Python 里面的空值 None。)
Python 函数是真正的好用。
(1)、Python 允许函数函数有默认值。如果函数被调用的时候没有指定参数,那么参数将使用默认值。不仅如此,通过使用命名参数还可以按照任何顺序指定参数。
让我们再看一下 approximate_size() 函数的声明:
<span style="font-family:Microsoft YaHei;color:#006600;">def approximate_size(size, a_kilobyte_is_1024_bytes=True):</span>
第二个参数 a_kilobyte_is_1024_bytes 指定了一个默认值 True。 意思是这个参数是 optional (可选的),你可以在调用的时候不指定它,Python 将看成你调用的时候使用了 True 作为第二个参数。
(2)、 Python允许指定变量名传值
<span style="font-family:Microsoft YaHei;color:#006600;">>>> from humansize import approximate_size >>> approximate_size(4000, a_kilobyte_is_1024_bytes=False) ① '4.0 KB' >>> approximate_size(size=4000, a_kilobyte_is_1024_bytes=False) ② '4.0 KB' >>> approximate_size(a_kilobyte_is_1024_bytes=False, size=4000) ③ '4.0 KB' >>> approximate_size(a_kilobyte_is_1024_bytes=False, 4000) ④ File "<stdin>", line 1 SyntaxError: non-keyword arg after keyword arg >>> approximate_size(size=4000, False) ⑤ File "<stdin>", line 1 SyntaxError: non-keyword arg after keyword arg</span>
①这个对 approximate_size() 函数的调用给第一个参数((size)指定了值 4000,并且给名为 a_kilobyte_is_1024_bytes 的参数指定了值 False。(那碰巧是第二个参数,但这没有关系,马上你就会了解到。)
②这个对 approximate_size() 函数的调用给名为 size 参数指定了值 4000,并为名为 a_kilobyte_is_1024_bytes 的参数指定了值 False。(这些命名参数碰巧和函数声明时列出的参数顺序一样,但同样不要紧。)
③这个对 approximate_size() 函数的调用给名为 a_kilobyte_is_1024_bytes 的参数指定了值 False,然后给名为 size 的参数指定了值 4000。(看到了没?我告诉过你顺序没有关系。)
④这个调用会失败,因为你在命名参数后面紧跟了一个非命名(位置的)的参数,这个一定不会工作。从左到右的读取参数列表,一旦你有一个命名的参数,剩下的参数也必须是命名的。
⑤这个调用也会失败,和前面一个调用同样的原因。 是不是很惊讶?别忘了,你给名为 size 的参数传入了值 4000,那么“显然的” False 这个值意味着对应了 a_kilobyte_is_1024_bytes 参数。但是 Python 不按照这种方式工作。只要你有一个命名参数,它右边的所有参数也都需要是命名参数。
注:Python函数往往返回 元组
2、 Python的注释
文档字符串#
你可以通过使用一个文档字符串(简称 docstring )的方式给 Python 添加文档注释。在这个程序中,这个 approximate_size() 函数有一个 docstring:
<span style="font-family:Microsoft YaHei;color:#006600;">def approximate_size(size, a_kilobyte_is_1024_bytes=True): '''Convert a file size to human-readable form. Keyword arguments: size -- file size in bytes a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024 if False, use multiples of 1000 Returns: string '''</span>
三重引号表示一个多行的字符串。在开始引号和结束引号之间的所有东西都属于一个单独的字符串的一部分,包括回车、前导空格、和其他引号字符。你可以在任何地方使用它们,但是你会发现大部分时候它们在定义 docstring (文档注释)的时候使用。☞三重引号也是一种容易的方法,用来定义一个同时包含单引号和双引号的字符串,就像 Perl 5 里面的 qq/.../ 一样。三重引号之间的所有东西都是这个函数的 docstring (文档字符串),用来用文档描述这个函数是做什么的。一个 docstring (文档字符串),如果有的话,必须是一个函数里面定义的第一个东西(也就是说,紧跟着函数声明的下一行)。 你不需要严格的给你的每个函数提供一个 docstring (文档字符串),但大部分时候你总是应该提供。我知道你在曾经使用过的每一种程序语言里面听说过这个,但是 Python 给你提供了额外的诱因:这个 docstring (文档字符串)就像这个函数的一个属性一样在运行时有效。☞很多 Python 的集成开发环境(ide)使用 docstring (文档字符串)来提供上下文敏感的文档,以便于当你输入一个函数名称的时候,它的 docstring 会以一个提示文本的方式显式出来。这可能会极其有用,但它只有在你写出好的 docstring (文档字符串)的时候才有用。
3、 Python变量不需要声明。需要使用的时候,声明和赋值是一起的。
4、 Python内置数据结构。
Python 有多种内置数据类型。以下是比较重要的一些:
Booleans[布尔型] 或为 True[真] 或为 False[假]。
Numbers[数值型] 可以是 Integers[整数](1 和 2)、Floats[浮点数](1.1 和 1.2)、Fractions[分数](1/2 和 2/3);甚至是 Complex Number[复数]。
Strings[字符串型] 是 Unicode 字符序列,例如: 一份 html 文档。
Bytes[字节] 和 Byte Arrays[字节数组], 例如: 一份 jpeg 图像文件。
Lists[列表] 是值的有序序列。
Tuples[元组] 是有序而不可变的值序列。
Sets[集合] 是装满无序值的包裹。
Dictionaries[字典] 是键值对的无序包裹。
当然,还有更多的类型。在 Python 中一切均为对象,因此存在像 module[模块]、 function[函数]、 class[类]、 method[方法]、 file[文件] 甚至 compiled code[已编译代码] 这样的类型。您已经见过这样一些例子:模块的 name、 函数的 docstrings 等等。将学到的包括 《类 与 迭代器》 中的 Classes[类],以及 《文件》 中的 Files[文件]。
Strings[字符串]和 Bytes[字节串]比较重要,也相对复杂,足以开辟独立章节予以讲述。让我们先看看其它类型。
① Booleans : True Fales (注意首字母大写!)
唯一要注意的是
{
由于 Python 2 的一些遗留问题,布尔值可以当做数值对待。True 为 1;False 为 0 。
<span style="font-family:Microsoft YaHei;color:#006600;">>>> True + True 2 >>> True - False 1 >>> True * False 0 >>> True / False Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: int division or modulo by zero</span>
}(Python3中不能用了)
②数值类型
数值类型是可畏的。有太多类型可选了。
Python 同时支持 Integer[整型] 和 Floating Point[浮点型] 数值。无任何类型声明可用于区分;Python 通过是否有 小数 点来分辨它们。
<pre name="code" class="python"><span style="font-family:Microsoft YaHei;color:#006600;">>>> type(1) ① <class 'int'> >>> isinstance(1, int) ② True >>> 1 + 1 ③ 2 >>> 1 + 1.0 ④ 2.0 >>> type(2.0) <class 'float'></span>
①可以使用 type() 函数来检测任何值或变量的类型。正如所料,1 为 int 类型。②同样,还可使用 isinstance() 函数判断某个值或变量是否为给定某个类型。③将一个 int 与一个 int 相加将得到一个 int 。④将一个 int 与一个 float 相加将得到一个 float 。Python 把 int 强制转换为 float 以进行加法运算;然后返回一个 float 类型的结果。
将整数强制转换为浮点数及反向转换#
正如刚才所看到的,一些运算符(如:加法)会根据需把整数强制转换为浮点数。也可自行对其进行强制转换。
<span style="font-family:Microsoft YaHei;color:#006600;">>>> float(2) ① 2.0 >>> int(2.0) ② 2 >>> int(2.5) ③ 2 >>> int(-2.5) ④ -2 >>> 1.12345678901234567890 ⑤ 1.1234567890123457 >>> type(1000000000000000) ⑥ <class 'int'></span>
①通过调用float() 函数,可以显示地将 int 强制转换为 float。②毫不出奇,也可以通过调用 int() 将 float 强制转换为 int 。③int() 将进行取整,而不是四舍五入。④对于负数,int() 函数朝着 0 的方法进行取整。它是个真正的取整(截断)函数,而不是 floor[地板]函数。⑤浮点数精确到小数点后 15 位。⑥整数可以任意大。☞Python 2 对于int[整型] 和 long[长整型] 采用不同的数据类型。int 数据类型受到 sys.maxint 的限制,因平台该限制也会有所不同,但通常是 232-1 。Python 3 只有一种整数类型,其行为方式很有点像 Python 2 的旧 long[长整数] 类型。
常见数值运算#
对数值可进行各种类型的运算。
<span style="font-family:Microsoft YaHei;color:#006600;">>>> 11 / 2 ① 5.5 >>> 11 // 2 ② 5 >>> −11 // 2 ③ −6 >>> 11.0 // 2 ④ 5.0 >>> 11 ** 2 ⑤ 121 >>> 11 % 2 ⑥ 1</span>
①/ 运算符执行浮点除法。即便分子和分母都是 int,它也返回一个 float 浮点数。②// 运算符执行古怪的整数除法。如果结果为正数,可将其视为朝向小数位取整(不是四舍五入),但是要小心这一点。③当整数除以负数, // 运算符将结果朝着最近的整数“向上”四舍五入。从数学角度来说,由于 −6 比 −5 要小,它是“向下”四舍五入,如果期望将结果取整为 −5,它将会误导你。④// 运算符并非总是返回整数结果。如果分子或者分母是 float,它仍将朝着最近的整数进行四舍五入,但实际返回的值将会是 float 类型。⑤** 运算符的意思是“计算幂”,112 结果为 121 。⑥% 运算符给出了进行整除之后的余数。11 除以 2 结果为 5 以及余数 1,因此此处的结果为 1。☞在 Python 2 中,运算符 / 通常表示整数除法,但是可以通过在代码中加入特殊指令,使其看起来像浮点除法。在 Python 3 中,/ 运算符总是表示浮点除法。
分数#
Python 并不仅仅局限于整数和浮点数类型。它可以完成你在高中阶段学过、但几乎已经全部忘光的所有古怪数学运算。
<span style="font-family:Microsoft YaHei;color:#006600;">>>> import fractions ① >>> x = fractions.Fraction(1, 3) ② >>> x Fraction(1, 3) >>> x * 2 ③ Fraction(2, 3) >>> fractions.Fraction(6, 4) ④ Fraction(3, 2) >>> fractions.Fraction(0, 0) ⑤ Traceback (most recent call last): File "<stdin>", line 1, in <module> File "fractions.py", line 96, in __new__ raise ZeroDivisionError('Fraction(%s, 0)' % numerator) ZeroDivisionError: Fraction(0, 0)</span>
①为启用 fractions 模块,必先引入 fractions 模块。
②为定义一个分数,创建一个 Fraction 对象并传入分子和分母。③可对分数进行所有的常规数学计算。运算返回一个新的 Fraction 对象。2 * (1/3) = (2/3)④Fraction 对象将会自动进行约分。(6/4) = (3/2)⑤在杜绝创建以零为分母的分数方面,Python 有着良好的敏感性。
还可在 Python 中进行基本的三角函数运算。<span style="font-family:Microsoft YaHei;color:#006600;">>>> import math >>> math.pi ① 3.1415926535897931 >>> math.sin(math.pi / 2) ② 1.0 >>> math.tan(math.pi / 4) ③ 0.99999999999999989</span>
①math 模块中有一个代表 π 的常量,表示圆的周长与直径之比率(圆周率)。②math 模块包括了所有的基本三角函数,包括:sin()、 cos()、tan() 及像 asin() 这样的变体函数。③然而要注意的是 Python 并不支持无限精度。tan(π / 4) 将返回 1.0,而不是 0.99999999999999989。布尔上下文环境中的数值#
可以在 if 这样的 布尔类型上下文环境中 使用数值。零值是 false[假],非零值是 true[真]。
<span style="font-family:Microsoft YaHei;color:#006600;">>>> def is_it_true(anything): ① ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(1) ② yes, it's true >>> is_it_true(-1) yes, it's true >>> is_it_true(0) no, it's false >>> is_it_true(0.1) ③ yes, it's true >>> is_it_true(0.0) no, it's false >>> import fractions >>> is_it_true(fractions.Fraction(1, 2)) ④ yes, it's true >>> is_it_true(fractions.Fraction(0, 1)) no, it's false</span>
①您知道可以在 Python 交互式 Shell 中定义自己的函数吗?只需在每行的结尾按 回车键 ,然后在某一空行按 回车键 结束。②在布尔类型上下文环境中,非零整数为真;零为假。③非零浮点数为真; 0.0 为假。请千万小心这一点!如果有轻微的四舍五入偏差(正如在前面小节中看到的那样,这并非不可能的事情),那么 Python 将测试 0.0000000000001 而不是 0 ,并将返回一个 True 值。④分数也可在布尔类型上下文环境中使用。无论 n 为何值,Fraction(0, n) 为假。所有其它分数为真。
③列表(list) →[1,2,3]
列表创建非常轻松:使用中括号包裹一系列以逗号分割的值即可。
<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_list = ['a', 'b', 'mpilgrim', 'z', 'example'] ① >>> a_list ['a', 'b', 'mpilgrim', 'z', 'example'] >>> a_list[0] ② 'a' >>> a_list[4] ③ 'example' >>> a_list[-1] ④ 'example' >>> a_list[-3] ⑤ 'mpilgrim'</span>
① 首先,创建一个包含 5 个元素的列表。要注意的是它们保持了最初的顺序。这并不是偶然的。列表是元素的有序集合。
② 列表可当做以零为基点的数组使用。非空列表的首个元素始终是 a_list[0] 。
③ 该 5 元素列表的最后一个元素是 a_list[4],因为列表(索引)总是以零为基点的。
④ 使用负索引值可从列表的尾部向前计数访问元素。任何非空列表的最后一个元素总是 a_list[-1] 。
⑤ 如果负数令你混淆,可将其视为如下方式: a_list[-n] == a_list[len(a_list) - n] 。因此在此列表中, a_list[-3] == a_list[5 - 3] == a_list[2]。
定义列表后,可从其中获取任何部分作为新列表。该技术称为对列表进行 切片 。
① 通过指定两个索引值,可以从列表中获取称作“切片”的某个部分。返回值是一个新列表,它包含列表(??切片)中所有元素,按顺序从第一个切片索引开始(本例中为 a_list[1]),截止但不包含第二个切片索引(本例中的 a_list[3])。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_list ['a', 'b', 'mpilgrim', 'z', 'example'] >>> a_list[1:3] ① ['b', 'mpilgrim'] >>> a_list[1:-1] ② ['b', 'mpilgrim', 'z'] >>> a_list[0:3] ③ ['a', 'b', 'mpilgrim'] >>> a_list[:3] ④ ['a', 'b', 'mpilgrim'] >>> a_list[3:] ⑤ ['z', 'example'] >>> a_list[:] ⑥ ['a', 'b', 'mpilgrim', 'z', 'example']</span>
② 如果切片索引之一或两者均为负数,切片操作仍可进行。如果有帮助的话,您可以这么思考:自左向右读取列表,第一个切片索引指明了想要的第一个元素,第二个切片索引指明了第一个不想要的元素。返回值是两者之间的任何值。 between.
③ 列表是以零为起点的,因此 a_list[0:3] 返回列表的头三个元素,从 a_list[0] 开始,截止到但不包括 a_list[3] 。
④ 如果左切片索引为零,可以将其留空而将零隐去。因此 a_list[:3] 与 a_list[0:3] 是完全相同的,因为起点 0 被隐去了。
⑤ 同样,如果右切片索引为列表的长度,也可以将其留空。因此 a_list[3:] 与 a_list[3:5] 是完全相同的,因为该列表有五个元素。此处有个好玩的对称现象。在这个五元素列表中, a_list[:3] 返回头三个元素,而 a_list[3:] 返回最后两个元素。事实上,无论列表的长度是多少, a_list[:n] 将返回头 n 个元素,而 a_list[n:] 返回其余部分。
⑥ 如果两个切片索引都留空,那么将包括列表所有的元素。但该返回值与最初的 a_list 变量并不一样。它是一个新列表,只不过恰好拥有完全相同的元素而已。a_list[:] 是对列表进行复制的一条捷径。
有四种方法可用于向列表中增加元素。
①+ 运算符连接列表以创建一个新列表。列表可包含任何数量的元素;没有大小限制(除了可用内存的限制)。然而,如果内存是个问题,那就必须知道在进行连接操作时,将在内存中创建第二个列表。在该情况下,新列表将会立即被赋值给已有变量 a_list 。因此,实际上该行代码包含两个步骤 — 连接然后赋值 — 当处理大型列表时,该操作可能(暂时)消耗大量内存。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_list = ['a'] >>> a_list = a_list + [2.0, 3] ① >>> a_list ② ['a', 2.0, 3] >>> a_list.append(True) ③ >>> a_list ['a', 2.0, 3, True] >>> a_list.extend(['four', 'Ω']) ④ >>> a_list ['a', 2.0, 3, True, 'four', 'Ω'] >>> a_list.insert(0, 'Ω') ⑤ >>> a_list ['Ω', 'a', 2.0, 3, True, 'four', 'Ω']</span>
②列表可包含任何数据类型的元素,单个列表中的元素无须全为同一类型。下面的列表中包含一个字符串、一个浮点数和一个整数。
③append() 方法向列表的尾部添加一个新的元素。(现在列表中有 四种 不同数据类型!)
④列表是以类的形式实现的。“创建”列表实际上是将一个类实例化。因此,列表有多种方法可以操作。extend() 方法只接受一个列表作为参数,并将该参数的每个元素都添加到原有的列表中。
⑤insert() 方法将单个元素插入到列表中。第一个参数是列表中将被顶离原位的第一个元素的位置索引。列表中的元素并不一定要是唯一的;比如说:现有两个各自独立的元素,其值均为 'Ω':,第一个元素 a_list[0] 以及最后一个元素 a_list[6] 。
☞a_list.insert(0, value) 就像是 Perl 中的 unshift() 函数。它将一个元素添加到列表的头部,所有其它的元素都被顶理原先的位置以腾出空间。
让我们进一步看看 append() 和 extend() 的区别。
①extend() 方法只接受一个参数,而该参数总是一个列表,并将列表 a_list 中所有的元素都添加到该列表中。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_list = ['a', 'b', 'c'] >>> a_list.extend(['d', 'e', 'f']) ① >>> a_list ['a', 'b', 'c', 'd', 'e', 'f'] >>> len(a_list) ② 6 >>> a_list[-1] 'f' >>> a_list.append(['g', 'h', 'i']) ③ >>> a_list ['a', 'b', 'c', 'd', 'e', 'f', ['g', 'h', 'i']] >>> len(a_list) ④ 7 >>> a_list[-1] ['g', 'h', 'i']</span>
②如果开始有个 3 元素列表,然后将它与另一个 3 元素列表进行 extend 操作,结果是将获得一个 6 元素列表。
③另一方面, append() 方法只接受一个参数,但可以是任何数据类型。在此,对一个 3 元素列表调用 append() 方法。
④如果开始的时候有个 6 元素列表,然后将一个列表 append[添加]上去,结果就会……得到一个 7 元素列表。为什么是 7 个?因为最后一个元素(刚刚 append[添加] 的元素) 本身是个列表 。列表可包含任何类型的数据,包括其它列表。这可能是你所需要的结果,也许不是。但如果这就是你想要的,那这就是你所得到的。
在列表中检索值
①如你所期望, count() 方法返回了列表中某个特定值出现的次数。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] >>> a_list.count('new') ① 2 >>> 'new' in a_list ② True >>> 'c' in a_list False >>> a_list.index('mpilgrim') ③ 3 >>> a_list.index('new') ④ 2 >>> a_list.index('c') ⑤ Traceback (innermost last): File "<interactive input>", line 1, in ?ValueError: list.index(x): x not in list</span>
② 如果你想知道的是某个值是否出现在列表中, in 运算符将会比使用 count() 方法要略快一些。in 运算符总是返回 True 或 False;它不会告诉你该值出现在什么位置。
③ 如果想知道某个值在列表中的精确位置,可调用 index() 方法。尽管可以通过第二个参数(以 0 为基点的)索引值来指定起点,通过第三个参数(以 0 基点的)索引来指定搜索终点,但缺省情况下它将搜索整个列表,
④ index() 方法将查找某值在列表中的第一次出现。在该情况下,'new' 在列表中出现了两次,分别为 a_list[2] 和 a_list[4],但 index() 方法将只返回第一次出现的位置索引值。
⑤ 可能 出乎 您的预期,如果在列表中没有找到该值,index() 方法将会引发一个例外。
等等,什么?是这样的:如果没有在列表中找到该值, index() 方法将会引发一个例外。这是 Python 语言最显著不同之处,其它多数语言将会返回一些无效的索引值(像是 -1)。当然,一开始这一点看起来比较讨厌,但我想您会逐渐欣赏它。这意味着您的程序将会在问题的源头处崩溃,而不是之后奇怪地、默默地崩溃。请记住, -1 是合法的列表索引值。如果 index() 方法返回 -1,可能会导致调整过程变得不那么有趣!
从列表中删除元素
列表可以自动拓展或者收缩。您已经看到了拓展部分。也有几种方法可从列表中删除元素。
① 可使用 del 语句从列表中删除某个特定元素。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] >>> a_list[1] 'b' >>> del a_list[1] ① >>> a_list ['a', 'new', 'mpilgrim', 'new'] >>> a_list[1] ② 'new'</span>
② 删除索引 1 之后再访问索引 1 将 不会 导致错误。被删除元素之后的所有元素将移动它们的位置以“填补”被删除元素所产生的“缝隙”。
不知道位置索引?这不成问题,您可以通过值而不是索引删除元素。
① 还可以通过 remove() 方法从列表中删除某个元素。remove() 方法接受一个 value 参数,并删除列表中该值的第一次出现。同样,被删除元素之后的所有元素将会将索引位置下移,以“填补缝隙”。列表永远不会有“缝隙”。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_list.remove('new') ① >>> a_list ['a', 'mpilgrim', 'new'] >>> a_list.remove('new') ② >>> a_list ['a', 'mpilgrim'] >>> a_list.remove('new') Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: list.remove(x): x not in list</span>
② 您可以尽情地调用 remove() 方法,但如果试图删除列表中不存在的元素,它将引发一个例外。
另一有趣的列表方法是 pop() 。pop() 方法是从列表删除元素的另一方法,但有点变化。
① 如果不带参数调用, pop() 列表方法将删除列表中最后的元素,并返回所删除的值。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_list = ['a', 'b', 'new', 'mpilgrim'] >>> a_list.pop() ① 'mpilgrim' >>> a_list ['a', 'b', 'new'] >>> a_list.pop(1) ② 'b' >>> a_list ['a', 'new'] >>> a_list.pop() 'new' >>> a_list.pop() 'a' >>> a_list.pop() ③ Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: pop from empty list</span>
② 可以从列表中 pop[弹出]任何元素。只需传给 pop() 方法一个位置索引值。它将删除该元素,将其后所有元素移位以“填补缝隙”,然后返回它删除的值。
③ 对空列表调用 pop() 将会引发一个例外。
☞不带参数调用的 pop() 列表方法就像 Perl 中的 pop() 函数。它从列表中删除最后一个元素并返回所删除元素的值。Perl 还有另一个函数 shift(),可用于删除第一个元素并返回其值;在 Python 中,该函数相当于 a_list.pop(0) 。
注:空列表为假;其它所有列表为真。
④元组(tuple) → (1,2,3)
元组 是不可变的列表。一旦创建之后,用任何方法都不可以修改元组。
<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_tuple = ("a", "b", "mpilgrim", "z", "example") ① >>> a_tuple ('a', 'b', 'mpilgrim', 'z', 'example') >>> a_tuple[0] ② 'a' >>> a_tuple[-1] ③ 'example' >>> a_tuple[1:3] ④ ('b', 'mpilgrim')</span>
①元组的定义方式和列表相同,除了整个元素的集合都用圆括号,而不是方括号闭合。
②和列表一样,元组的元素都有确定的顺序。元组的索引也是以零为基点的,和列表一样,因此非空元组的第一个元素总是 a_tuple[0] 。
③负的索引从元组的尾部开始计数,这和列表也是一样的。
④和列表一样,元组也可以进行切片操作。对列表切片可以得到新的列表;对元组切片可以得到新的元组。
元组和列表的主要区别是元组不能进行修改。用技术术语来说,元组是 不可变更 的。从实践的角度来说,没有可用于修改元组的方法。列表有像 append()、 extend()、 insert()、remove() 和 pop() 这样的方法。这些方法,元组都没有。可以对元组进行切片操作(因为该方法创建一个新的元组),可以检查元组是否包含了特定的值(因为该操作不修改元组),还可以……就那么多了。
<span style="font-family:Microsoft YaHei;color:#006600;"># continued from the previous example >>> a_tuple ('a', 'b', 'mpilgrim', 'z', 'example') >>> a_tuple.append("new") ① Traceback (innermost last): File "<interactive input>", line 1, in ?AttributeError: 'tuple' object has no attribute 'append' >>> a_tuple.remove("z") ② Traceback (innermost last): File "<interactive input>", line 1, in ?AttributeError: 'tuple' object has no attribute 'remove' >>> a_tuple.index("example") ③ 4 >>> "z" in a_tuple ④ True</span>
①无法向元组添加元素。元组没有 append() 或 extend() 方法。
②不能从元组中删除元素。元组没有 remove() 或 pop() 方法。
③可以 在元组中查找元素,由于该操作不改变元组。
④还可以使用 in 运算符检查某元素是否存在于元组中。
那么元组有什么好处呢?
元组的速度比列表更快。如果定义了一系列常量值,而所需做的仅是对它进行遍历,那么请使用元组替代列表。
对不需要改变的数据进行“写保护”将使得代码更加安全。使用元组替代列表就像是有一条隐含的 assert 语句显示该数据是常量,特别的想法(及特别的功能)必须重写。(??)
一些元组可用作字典键(特别是包含字符串、数值和其它元组这样的不可变数据的元组)。列表永远不能当做字典键使用,因为列表不是不可变的。
☞元组可转换成列表,反之亦然。内建的 tuple() 函数接受一个列表参数,并返回一个包含同样元素的元组,而 list() 函数接受一个元组参数并返回一个列表。从效果上看, tuple() 冻结列表,而 list() 融化元组。
布尔上下文环境中的元组#
可以在 if 这样的 布尔类型上下文环境中 使用元组。
<pre name="code" class="python"><span style="font-family:Microsoft YaHei;color:#006600;">>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(()) ① no, it's false >>> is_it_true(('a', 'b')) ② yes, it's true >>> is_it_true((False,)) ③ yes, it's true >>> type((False)) ④ <class 'bool'> >>> type((False,)) <class 'tuple'></span>
①在布尔类型上下文环境中,空元组为假值。
②任何至少包含一个上元素的元组为真值。
③任何至少包含一个上元素的元组为真值。元素的值无关紧要。不过此处的逗号起什么作用呢?
④为创建单元素元组,需要在值之后加上一个逗号。没有逗号,Python 会假定这只是一对额外的圆括号,虽然没有害处,但并不创建元组。
###同时赋多个值#
以下是一种很酷的编程捷径:在 Python 中,可使用元组来一次赋多值。
<pre name="code" class="python"><span style="font-family:Microsoft YaHei;color:#006600;">>>> v = ('a', 2, True) >>> (x, y, z) = v ① >>> x 'a' >>> y 2 >>> z True</span>
①v 是一个三元素的元组,而 (x, y, z) 是包含三个变量的元组。将其中一个赋值给另一个将会把 v 中的每个值按顺序赋值给每一个变量。
该特性有多种用途。假设需要将某个名称指定某个特定范围的值。可以使用内建的 range() 函数进行多变量赋值以快速地进行连续变量赋值。
<pre name="code" class="python"><span style="font-family:Microsoft YaHei;color:#006600;">>>> (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7) ① >>> MONDAY ② 0 >>> TUESDAY 1 >>> SUNDAY 6</span>
①内建的 range() 函数构造了一个整数序列。(从技术上来说, range() 函数返回的既不是列表也不是元组,而是一个 迭代器,但稍后您将学到它们的区别。) MONDAY、 TUESDAY、 WEDNESDAY、 THURSDAY、 FRIDAY、 SATURDAY 和 SUNDAY 是您所定义的变量。(本例来自于 calendar 模块,该短小而有趣的模块打印日历,有点像 unix 程序 cal 。该 calendar 模块为星期数定义了整数常量。
②现在,每个变量都有其值了: MONDAY 为 0, TUESDAY 为 1,如此类推。
还可以使用多变量赋值创建返回多值的函数,只需返回一个包含所有值的元组。调用者可将返回值视为一个简单的元组,或将其赋值给不同的变量。许多标准 Python 类库这么干,包括在下一章将学到的 os 模块。
⑤集合(set)→{1,2,3}
集合set 是装有独特值的无序“袋子”。一个简单的集合可以包含任何数据类型的值。如果有两个集合,则可以执行像联合、交集以及集合求差等标准集合运算。
创建集合
重中之重。创建集合非常简单。
① 要创建只包含一个值的集合,仅需将该值放置于花括号之间。({})。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_set = {1} ① >>> a_set {1} >>> type(a_set) ② <class 'set'> >>> a_set = {1, 2} ③ >>> a_set {1, 2}</span>
② 实际上,集合以 类 的形式实现,但目前还无须考虑这一点。
③ 要创建多值集合,请将值用逗号分开,并用花括号将所有值包裹起来。
还可以 列表 为基础创建集合。
① 要从列表创建集合,可使用 set() 函数。(懂得如何实现集合的学究可能指出这实际上并不是调用某个函数,而是对某个类进行实例化。我保证在本书稍后的地方将会学到其中的区别。目前而言,仅需知道 set() 行为与函数类似,以及它返回一个集合。)<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_list = ['a', 'b', 'mpilgrim', True, False, 42] >>> a_set = set(a_list) ① >>> a_set ② {'a', False, 'b', True, 'mpilgrim', 42} >>> a_list ③ ['a', 'b', 'mpilgrim', True, False, 42]</span>
② 正如我之前提到的,简单的集合可以包括任何数据类型的值。而且,如我之前所提到的,集合是 无序的。该集合并不记得用于创建它的列表中元素的最初顺序。如果向集合中添加元素,它也不会记得添加的顺序。
③ 初始的列表并不会发生变化。
还没有任何值?没有问题。可以创建一个空的集合。
① 要创建空集合,可不带参数调用 set() 。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_set = set() ① >>> a_set ② set() >>> type(a_set) ③ <class 'set'> >>> len(a_set) ④ 0 >>> not_sure = {} ⑤ >>> type(not_sure) <class 'dict'></span>
② 打印出来的空集合表现形式看起来有点儿怪。也许,您期望看到一个 {} 吧 ?该符号表示一个空的字典,而不是一个空的集合。本章稍后您将学到关于字典的内容。
③ 尽管打印出的形式奇怪,这 确实是 一个集合……
④ …… 同时该集合没有任何成员。
⑤ 由于从 Python 2 沿袭而来历史的古怪规定,不能使用两个花括号来创建空集合。该操作实际创建一个空字典,而不是一个空集合。
修改集合
有两种方法可向现有集合中添加值: add() 方法和 update() 方法。
① add() 方法接受单个可以是任何数据类型的参数,并将该值添加到集合之中。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_set = {1, 2} >>> a_set.add(4) ① >>> a_set {1, 2, 4} >>> len(a_set) ② 3 >>> a_set.add(1) ③ >>> a_set {1, 2, 4} >>> len(a_set) ④ 3</span>
② 该集合现在有三个成员了。
③ 集合是装 唯一值 的袋子。如果试图添加一个集合中已有的值,将不会发生任何事情。将不会引发一个错误;只是一条空操作。
④ 该集合 仍然 只有三个成员。
① update() 方法仅接受一个集合作为参数,并将其所有成员添加到初始列表中。其行为方式就像是对参数集合中的每个成员调用 add() 方法。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_set = {1, 2, 3} >>> a_set {1, 2, 3} >>> a_set.update({2, 4, 6}) ① >>> a_set ② {1, 2, 3, 4, 6} >>> a_set.update({3, 6, 9}, {1, 2, 3, 5, 8, 13}) ③ >>> a_set {1, 2, 3, 4, 5, 6, 8, 9, 13} >>> a_set.update([10, 20, 30]) ④ >>> a_set {1, 2, 3, 4, 5, 6, 8, 9, 10, 13, 20, 30}</span>
② 由于集合不能包含重复的值,因此重复的值将会被忽略。
③ 实际上,可以带任何数量的参数调用 update() 方法。如果调用时传递了两个集合, update() 将会被每个集合中的每个成员添加到初始的集合当中(丢弃重复值)。
④ update() 方法还可接受一些其它数据类型的对象作为参数,包括列表。如果调用时传入列表,update() 将会把列表中所有的元素添加到初始集合中。
从集合中删除元素#
有三种方法可以用来从集合中删除某个值。前两种,discard() 和 remove() 有细微的差异。
① discard() 接受一个单值作为参数,并从集合中删除该值。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} >>> a_set {1, 3, 36, 6, 10, 45, 15, 21, 28} >>> a_set.discard(10) ① >>> a_set {1, 3, 36, 6, 45, 15, 21, 28} >>> a_set.discard(10) ② >>> a_set {1, 3, 36, 6, 45, 15, 21, 28} >>> a_set.remove(21) ③ >>> a_set {1, 3, 36, 6, 45, 15, 28} >>> a_set.remove(21) ④ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 21</span>
② 如果针对一个集合中不存在的值调用 discard() 方法,它不进行任何操作。不产生错误;只是一条空指令。
③ remove() 方法也接受一个单值作为参数,也从集合中将其删除。
④ 区别在这里:如果该值不在集合中,remove() 方法引发一个 KeyError 例外。
就像列表,集合也有个 pop() 方法。
①pop() 方法从集合中删除某个值,并返回该值。然而,由于集合是无序的,并没有“最后一个”值的概念,因此无法控制删除的是哪一个值。它基本上是随机的。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} >>> a_set.pop() ① 1 >>> a_set.pop() 3 >>> a_set.pop() 36 >>> a_set {6, 10, 45, 15, 21, 28} >>> a_set.clear() ② >>> a_set set() >>> a_set.pop() ③ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'pop from an empty set'</span>
② clear() 方法删除集合中 所有 的值,留下一个空集合。它等价于 a_set = set(),该语句创建一个新的空集合,并用之覆盖 a_set 变量的之前的值。
③ 试图从空集合中弹出某值将会引发 KeyError 例外。
常见集合操作#
Python 的 集合 类型支持几种常见的运算。
① 要检测某值是否是集合的成员,可使用 in 运算符。其工作原理和列表的一样。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_set = {2, 4, 5, 9, 12, 21, 30, 51, 76, 127, 195} >>> 30 in a_set ① True >>> 31 in a_set False >>> b_set = {1, 2, 3, 5, 6, 8, 9, 12, 15, 17, 18, 21} >>> a_set.union(b_set) ② {1, 2, 195, 4, 5, 6, 8, 12, 76, 15, 17, 18, 3, 21, 30, 51, 9, 127} >>> a_set.intersection(b_set) ③ {9, 2, 12, 5, 21} >>> a_set.difference(b_set) ④ {195, 4, 76, 51, 30, 127} >>> a_set.symmetric_difference(b_set) ⑤ {1, 3, 4, 6, 8, 76, 15, 17, 18, 195, 127, 30, 51}</span>
② union() 方法返回一个新集合,其中装着 在两个 集合中出现的元素。
③ intersection() 方法返回一个新集合,其中装着 同时 在两个集合中出现的所有元素。
④ difference() 方法返回的新集合中,装着所有在 a_set 出现但未在 b_set 中的元素。
⑤ symmetric_difference() 方法返回一个新集合,其中装着所有 只在其中一个 集合中出现的元素。
这三种方法是对称的。
① a_set 与 b_set 的对称差分 看起来 和b_set 与 a_set 的对称差分不同,但请记住:集合是无序的。任何两个包含所有同样值(无一遗漏)的集合可认为是相等的。<span style="font-family:Microsoft YaHei;color:#006600;"># continued from the previous example >>> b_set.symmetric_difference(a_set) ① {3, 1, 195, 4, 6, 8, 76, 15, 17, 18, 51, 30, 127} >>> b_set.symmetric_difference(a_set) == a_set.symmetric_difference(b_set) ② True >>> b_set.union(a_set) == a_set.union(b_set) ③ True >>> b_set.intersection(a_set) == a_set.intersection(b_set) ④ True >>> b_set.difference(a_set) == a_set.difference(b_set) ⑤ False</span>
② 而这正是这里发生的事情。不要被 Python Shell 对这些集合的输出形式所愚弄了。它们包含相同的值,因此是相等的。
③ 对两个集合的 Union[并集]操作也是对称的。
④ 对两个集合的 Intersection[交集]操作也是对称的。
⑤ 对两个集合的 Difference[求差]操作不是对称的。这是有意义的;它类似于从一个数中减去另一个数。操作数的顺序会导致结果不同。
最后,有几个您可能会问到的问题。
① a_set 是 b_set 的 子集 — 所有 a_set 的成员均为 b_set 的成员。<span style="font-family:Microsoft YaHei;color:#006600;">>>> a_set = {1, 2, 3} >>> b_set = {1, 2, 3, 4} >>> a_set.issubset(b_set) ① True >>> b_set.issuperset(a_set) ② True >>> a_set.add(5) ③ >>> a_set.issubset(b_set) False >>> b_set.issuperset(a_set) False</span>
② 同样的问题反过来说, b_set 是 a_set 的 超集,因为 a_set 的所有成员均为 b_set 的成员。
③ 一旦向 a_set 添加一个未在 b_set 中出现的值,两项测试均返回 False 。
在布尔类型上下文环境中,空集合为假值。
任何至少包含一个上元素的集合为真值。
任何至少包含一个上元素的集合为真值。元素的值无关紧要。
⑥字典(dict)→{a:1,b:2,c:{a:1,b:2},d:(1,2,3)}
字典并非只能用于字符串。字典的值可以是任何数据类型,包括整数、布尔值、任何对象,甚至是其它的字典。而且就算在同一字典中,所有的值也无须是同一类型,您可根据需要混合匹配。字典的键要严格得多,可以是字符串、整数和其它一些类型。在同一字典中也可混合、匹配使用不同数据类型的键。
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
在布尔类型上下文环境中,空字典为假值。
至少包含一个键值对的字典为真值。
基本数据类型就这点了,确实初步可以看出比java c 这种强太多,但是功能多也得记住才好用啊!
ps:Python大名鼎鼎的缩进编码应该不用提示了吧