内置类型:元组
元组是不可变的
元组是一组值的序列。 其中的值可以是任意类型, 使用整数索引, 因此从这点上看,元组与列表非常相似。 二者不同之处在于元组的不可变性。
语法上,元组是用逗号隔开一系列值:
>>> t = 'a', 'b', 'c', 'd', 'e'
# 虽然并非必须,元组通常用括号括起来:
>>> t = ('a', 'b', 'c', 'd', 'e')
# 使用单一元素创建元组时,需要在结尾处添加一个逗号:
>>> t1 = 'a',
>>> type(t1)
<class 'tuple'>
# 将值放置在括号中并不会创建元组:
>>> t2 = ('a')
>>> type(t2)
<class 'str'>
# 另一个创建元组的方法是使用内建函数 tuple 。 在没有参数传递时,它会创建一个空元组
>>> t = tuple()
>>> t
()
# 如果实参是一个序列(字符串、列表或者元组),结果将是一个包含序列内元素的元组。
>>> t = tuple('lupins')
>>> t
('l', 'u', 'p', 'i', 'n', 's')
# 列表的大多数操作符同样也适用于元组。 方括号运算符将索引一个元素:
>>> t = ('a', 'b', 'c', 'd', 'e')
>>> t[0]
'a'
# 切片运算符选取一个范围内的元素:
>>> t[1:3]
('b', 'c')
# 但是,如果你试图元组中的一个元素,会得到错误信息:
>>> t[0] = 'A'
TypeError: object doesn't support item assignment
# 因为元组是不可变的,你无法改变其中的元素。 但是可以使用其他元组替换现有元组:
>>> t = ('A',) + t[1:]
>>> t
('A', 'b', 'c', 'd', 'e')
# 这个语句创建了一个新元组,然后让 t 引用该元组。
# 关系型运算符也适用于元组和其他序列; Python 会首先比较序列中的第一个元素,如果它们相等,就继续比较下一组元素,以此类推,直至比值不同。 其后的元素(即便是差异很大)也不会再参与比较。
>>> (0, 1, 2) < (0, 3, 4)
True
>>> (0, 1, 2000000) < (0, 3, 4)
True
# 元组赋值
# 两个变量互换值的操作通常很有用。 按照传统的赋值方法,你需要使用一个临时变量。 例如,为了交换 a 和 b 的值:
>>> temp = a
>>> a = b
>>> b = temp
# 这个方法很繁琐;通过元组赋值来实现更为优雅:
>>> a, b = b, a
# 左侧的变量数和右侧值的数目必须相同:
>>> a, b = 1, 2, 3
ValueError: too many values to unpack
>>> addr = 'monty@python.org'
>>> uname, domain = addr.split('@')
# 元组作为返回值
# 函数多个返回值
严格地说,一个函数只能返回一个值,但是如果这个返回值是元组,其效果等同于返回多个值。
# 内建函数 divmod 接受两个实参,返回包含两个值的元组:商和余数。 你可以使用元组来存储返回值:
>>> t = divmod(7, 3)
>>> t
(2, 1)
# 或者使用元组赋值分别存储它们:
>>> quot, rem = divmod(7, 3)
>>> quot
2
>>> rem
1
# 下面是一个返回元组作为结果的函数例子:
def min_max(t):
return min(t), max(t)
# 可变长度参数元组
# 函数可以接受可变数量的参数。 以 “*” 开头的形参将输入的参数 汇集 到一个元组中。
def printall(*args):
print(args)
# 汇集形参可以使用任意名字,但是习惯使用 args。 以下是这个函数的调用效果:
>>> printall(1, 2.0, '3')
(1, 2.0, '3')
# 与汇集相对的,是 分散(scatter) 。
# 如果你有一个值序列,并且希望将其作为多个参数传递给一个函数, 你可以使用运算符*。 例如,divmod 只接受两个实参; 元组则无法作为参数传递进去:
>>> t = (7, 3)
>>> divmod(t)
TypeError: divmod expected 2 arguments, got 1
>>> divmod(*t)
(2, 1)
# 许多内建函数使用了可变长度参数元组。 例如,max 和 min 就可以接受任意数量的实参:
>>> max(1, 2, 3)
3
# 但是 sum 不行:
>>> sum(1, 2, 3)
TypeError: sum expected at most 2 arguments, got 3
# 列表和元组
zip是一个内建函数,可以接受将两个或多个序列组,并返回一个元组列表, 其中每个元组包含了各个序列中相对位置的一个元素。 这个函数的名称来自名词拉链(zipper),后者将两片链齿连接拼合在一起。
# 对一个字符串和列表使用 zip 函数:
>>> s = 'abc'
>>> t = [0, 1, 2]
>>> zip(s, t)
<zip object at 0x7f7d0a9e7c48>
# 输出的结果是一个 zip 对象,包含了如何对其中元素进行迭代的信息。 zip 函数最常用于 for 循环:
使用内建函数 zip 所返回的结果;它是一个可以对元组序列进行迭代的对象。
>>> for pair in zip(s, t):
... print(pair)
...
('a', 0)
('b', 1)
('c', 2)
zip对象是迭代器的一种,即任何能够按照某个序列迭代的对象。 迭代器在某些方面与列表非常相似,但不同之处在于,你无法通过索引来选择迭代器中的某个元素。
如果你想使用列表操作符和方法,你可以通过 zip 对象创建一个列表:
>>> list(zip(s, t))
[('a', 0), ('b', 1), ('c', 2)]
结果就是一个包含若干元组的列表;在这个例子中,每个元组又包含了字符串中的一个字符和列表 中对应的一个元素。
如果用于创建的序列长度不一,返回对象的长度以最短序列的长度为准。
>>> list(zip('Anne', 'Elk'))
[('A', 'E'), ('n', 'l'), ('n', 'k')]
您可以在 for 循环中使用元组赋值,遍历包含元组的列表:
t = [('a', 0), ('b', 1), ('c', 2)]
for letter, number in t:
print(number, letter)
每次循环时,Python 会选择列表中的下一个元组, 并将其内容赋给 letter 和 number 。循环的输出是:
0 a
1 b
2 c
如果将 zip 、for 循环和元组赋值结合起来使用,你会得到一个可以同时遍历两个(甚至多个)序列的惯用法。 例如,has_match 接受两个序列 t1 和 t2 , 如果存在索引 i 让 t1[i] == t2[i] ,则返回 True :
def has_match(t1, t2):
for x, y in zip(t1, t2):
if x == y:
return True
return False
如果需要遍历一个序列的元素以及其索引号,您可以使用内建函数 enumerate :
for index, element in enumerate('abc'):
print(index, element)
enumerate的返回结果是一个枚举对象(enumerate object),可迭代一个包含若干个对的序列; 每个对包含了(从0开始计数)的索引和给定序列中的对应元素。 在这个例子中,输出结果是:
0 a
1 b
2 c
和前一个示例的结果一样。
字典和元组
字典和元组
字典有一个叫做 items 的方法,它返回由多个元组组成的序列,其中每个元组是一个键值对。
>>> d = {'a':0, 'b':1, 'c':2}
>>> t = d.items()
>>> t
dict_items([('c', 2), ('a', 0), ('b', 1)])
其结果是一个 dict_items 对象,这是一个对键值对进行迭代的迭代器。 你可以在 for 循环中像这样使用它:
>>> for key, value in d.items():
... print(key, value)
...
c 2
a 0
b 1
由于是字典生成的对象,你应该也猜到了这些项是无序的。
另一方面,您可以使用元组的列表初始化一个新的字典:
>>> t = [('a', 0), ('c', 2), ('b', 1)]
>>> d = dict(t)
>>> d
{'a': 0, 'c': 2, 'b': 1}
将 dict 和 zip 结合使用,可以很简洁地创建一个字典:
>>> d = dict(zip('abc', range(3)))
>>> d
{'a': 0, 'c': 2, 'b': 1}
字典的 update 方法也接受元组列表,并将其作为键值对添加到已有的字典中去。
在字典中使用元组作为键(主要因为无法使用列表)的做法很常见。 例如,一个电话簿可能会基于用户的姓-名对,来映射至号码。 假设我们已经定义了 last 、 first 和 number 三个变量, 我们可以这样实现映射:
directory[last, first] = number
方括号中的表达式是一个元组。我们可以通过元组赋值来遍历这个字典:
for last, first in directory:
print(first, last, directory[last,first])
该循环遍历电话簿中的键,它们其实是元组。 循环将元组的元素赋给 last 和 first , 然后打印出姓名和对应的电话号码。
序列嵌套
在很多情况下,不同类型的序列(字符串、列表、元组)可以互换使用。
列表比元组更常用,主要是因为它们是可变的。 但是有些情况下,你可能更倾向于使用元组:
- 在一些情况下(例如 return 语句),从句式上生成一个元组比列表要简单。
- 如果你想使用一个序列作为字典的键,那么你必须使用元组或字符串这样的不可变类型。
- 如果你向函数传入一个序列作为参数,那么使用元组可以降低由于别名而产生的意外行为的可能性。
由于元组的不可变性,它们没有类似(sort) 和 (reverse)这样修改现有列表的方法。 然而 Python 提供了内建函数 sorted 和 reversed ,前者可以接受任意序列,并返回一个正序排列的新列表,后者则接受一个序列,返回一个可逆序迭代列表的迭代器。
迭代器(iterator):
一个可以对序列进行迭代的对象,但是并不提供列表操作符和方法。
zip 对象:
使用内建函数 zip 所返回的结果;它是一个可以对元组序列进行迭代的对象。
随机数
random模块提供了生成伪随机数(下文中简称为“随机数”)的函数。
函数 random 返回一个 0.0 到 1.0 之间的随机浮点数(包括 0.0 ,但是不包括 1.0 )。 每次调用 random ,你获得一个长序列中的下一个数。 举个例子,运行此循环:
import random
for i in range(10):
x = random.random()
print(x)
函数 randint 接受参数 low 和 high , 返回一个 low 和 high 之间的整数(两个都包括)。
>>> random.randint(5, 10)
5
>>> random.randint(5, 10)
9
你可以使用 choice ,从一个序列中随机选择一个元素:
>>> t = [1, 2, 3]
>>> random.choice(t)
2
>>> random.choice(t)
3
random模块提供的函数,还可以生成符合高斯、指数、伽马等连续分布的随机值。
可选形参
def print_most_common(hist, num=10):
t = most_common(hist)
print('The most common words are:')
for freq, word in t[:num]:
print(word, freq, sep='\t')
第一个形参是必须的;第二个是可选的。 num 的默认值(default value)是10。
如果你只提供了一个实参:
print_most_common(hist)
num将使用默认值。如果你你提供两个实参:
print_most_common(hist, 20)
num获得实参的值。换句话说,可选实参覆盖(overrides)了默认值。
如果一个函数同时有必选和可选两类形参,则所有的必选形参必须首先出现,可选形参紧随其后。
网友评论