在 C++ 和 Java 中,容器是需要你显式命名并构造的 library class。 Python 则把容器直接放进了语法:[1, 2]、{"a": 1} 和 {1, 2} 都是字面量,in 和 len() 可以作用于它们全部, 切片可以作用于各种序列,而且这些都不需要导入任何东西。 列表、元组、字典和集合都是基础数据类型。

列表

for 语句会直接遍历列表,而不是先遍历一串数字索引:

# list.py

odds = [1, 3, 5, 7, 9, 11]
print(odds)
#: [1, 3, 5, 7, 9, 11]
odds.append(13)
for x in odds:
    print(x)
#: 1
#: 3
#: 5
#: 7
#: 9
#: 11
#: 13

第一行创建一个 list。 append() 向 odds 添加新元素。 list 会自动调整自身大小。 for 语句遍历 odds, 因此 x 会依次取得 list 中的每个值。

list 可以容纳任意种类的对象,是一个有序、可变的序列。 索引从零开始,负索引从末尾倒数。 切片(slice) [start:stop:step] 会复制一个子区间,其中不包含 stop:

# slicing.py

xs = [10, 20, 30, 40, 50]
print(xs[0], xs[-1])  # First and last
#: 10 50
print(xs[1:3])  # The stop index is excluded
#: [20, 30]
print(xs[:2])  # From the start
#: [10, 20]
print(xs[2:])  # To the end
#: [30, 40, 50]
print(xs[::2])  # Every second item
#: [10, 30, 50]
print(xs[::-1])  # Reversed
#: [50, 40, 30, 20, 10]

切片适用于任何序列,包括字符串和元组。

列表可以增长、收缩,也能回答关于自身的问题:

# list_ops.py

xs = [10, 20, 30]
xs.append(40)  # Add one item at the end
xs.extend([50, 60])  # Add every item of an iterable
xs.insert(1, 15)  # Insert before index 1
print(xs, len(xs))
#: [10, 15, 20, 30, 40, 50, 60] 7
xs.remove(15)  # Remove the first item equal to 15
del xs[0]  # Remove by index
print(xs, 30 in xs)
#: [20, 30, 40, 50, 60] True

append() 会把它的参数作为单个元素加入, 因此 xs.append([1, 2]) 会把一个 list 放进另一个 list。 extend() 则会逐个加入参数中的每一项。

sorted() 可以从任意 iterable 构造一个新的已排序列表。 list.sort() 会原地重新排列列表,并返回 None:

# sorting.py

words = ["pear", "Fig", "apple"]
print(sorted(words))  # A new list; words is untouched
#: ['Fig', 'apple', 'pear']
print(words)
#: ['pear', 'Fig', 'apple']
print(words.sort())  # Sorts in place and returns None
#: None
print(words)
#: ['Fig', 'apple', 'pear']
print(sorted(words, reverse=True))
#: ['pear', 'apple', 'Fig']

sorted(x) 返回排序后的结果,而 x.sort() 返回 None, 因此 x = x.sort() 会把 x 绑定到 None,从而丢掉原来的列表。 大写字母排在小写字母之前,因为 Python 按 code point 比较字符串。 函数会说明如何使用 key= 改变这一行为。

list 并不要求所有元素属于同一种类型。 由于每个槽位保存的只是你放进去的某个对象的引用, 同一个 list 可以同时混合字符串、数字、None 和其他容器:

# mixed_types.py

mixed = [1, "two", 3.0, True, None, [5, 6]]
for item in mixed:
    print(item, type(item).__name__)
#: 1 int
#: two str
#: 3.0 float
#: True bool
#: None NoneType
#: [5, 6] list

混合类型很方便,但也很容易被滥用。 一个混合多种类型的 list,通常意味着每个元素都需要不同的处理逻辑。 这种情况通常用 tuple、data class, 或者若干个各自只保存一种类型的独立列表,表达得更好。

有两个列表操作很容易带来意外。 * 重复的是引用,而不是复制引用所指向的对象, 因此用这种方式构造出来的网格,实际上是三个名称共同指向同一行: