Lists
list 容器类型存放的是序列数据。之前说过 str 是不可变类型,list 是可变类型,也就是说我们可以修改 list 里面存放的内容。
a = [1, 2, 3]
print(len(a)) #3
上面的代码展示了如何创建一个 list,list 可以存放重复的元素;len 函数可以返回 list 中含有的元素个数。
在 Python 中有个关键字 is,它是用来判断两个变量是否在内存中的地址是相同的。让我们看看下面的代码:
a = b = 11
print(a is b) # True
print([1] is [1]) # False
上面的代码明确地告诉了我们,即使我们创建了两个 list,里面存放的内容一样,那它们也是两个不一样的 list,也就是说,它们俩在内存中的地址是不一样的;或者说,改变其中一个 list 的内容不会影响另一个 list。
a 和 b 既然有同样的内存地址,如果改变了 a 的值,会不会也把 b 改了呢?当然不会,因为 int 是不可变类型,如果改变了 a 的值,那么 a 就有了新的内存地址,当然和 b 不一样了。
为 list 添加元素,Python 提供了三个常用的方法:append,insert 以及列表连接或者说相加操作。
# append
list1 = [1, 2, 3]
list1.append(4)
print(list1) # [1, 2, 3, 4]
# insert
list2 = [1, 2, 4]
list2.insert(2, 3)
print(list2) # [1, 2, 3, 4]
# list + list
print([1, 2, 3] + [4]) # [1, 2, 3, 4]
三个方法创建了三个内容一样的 list。但这里面 append 是最快的。因为 insert 需要先找到待插入的索引位置,再插入元素;list 连接操作需要创建一个新的 list 然后再插入待连接的两个 list 的内容。
Python 还提供了另一个方法,extend 函数,它允许你一次添加多个元素到给定的 list 中,但它的内部实现机制更加有效。
下面我们来看看如何删除一个元素:
a = [1, 2, 3, 4]
a.remove(1)
print(a) # [2, 3, 4]
remove 函数不会创建一个新的 list,也就是说,remove 是在原有的 list 上进行删除操作,不需要拷贝原有内容,也就减少了内存的开销。
下面看看如何反转一个 list:
a = [1, 2, 3, 4]
a.reverse()
print(a) # [4, 3, 2, 1]
reverse 函数和 remove 函数一样,是在原来的 list 上直接操作,不会创建新的 list。
下面看看排序:
a = [4, 2, 1, 3]
a.sort()
print(a) # [1, 2, 3, 4]
sort 函数也一样,在原来的 list 进行修改排序,排序结果为升序。如果 list 里面存放的是 str 类型,那么将按照字母升序方式进行排序。sort 函数假定认为 list 中的元素是可比较的,也就是说,如果任意的对象都能比较大小,那就可以使用 list 的 sort 方法。
查找元素:通过 index 函数我们可以找到指定元素的索引
print([1, 1, 3].index(1)) # 0
print([2, 2, 6].index(2, 1)) # 1
index 一个参数的版本将返回所要查找元素第一次出现的索引值。像大多数编程语言一样,index 返回的索引值的基数是从 0 开始的。
Stacks
stack 也就是栈结构,它的特性就是后进先出。想象一份报纸一份报纸的堆叠起来,最后放上去的报纸一定先被拿走。
Python 中的可以用 list 来实现 stack。append 函数添加元素到栈顶,pop 函数移除最后添加的元素。
s = [1]
s.append(2) # [1, 2]
s.pop() # 2 s的值为:[1]
s.pop() # 1 s的值为:[]
由于 Python 实现 list 的机制很高效,所以完全没有必要再去创建或者引用第三方实现的 stack,用 list 即可。
Sets
set 是一个基本的数据结构,大多数流行的编程语言中都有。在 MapReduce 和 Apache Spark 中甚至还把 set 当作了基本类型来使用。set 的特性有两个,1.元素无序,2.元素无重复。
set 像 list 和 tuple 一样,是个容器类型,里面可以存放基本类型,或者 objects,tuples。然而有一个必要条件就是,存放在 set 中的元素必须是可哈希的,也就是说每个元素都有一个关联的哈希值。一个对象的哈希值是永远不会变的,哈希值被用来比较两个对象。
s1 = "abc"
s2 = "def"
s3 = "ghi"
print(hash(s1)) # -2789987385810387064
print(hash(s2)) # -1296788039880291611
set1 = {s1, s2, s3}
print(set1) # {'abc', 'ghi', 'def'}
l1 = [s1, s2]
l2 = [s3]
set2 = {l1, l2} # TypeError: unhashable type: 'list'
上面的代码很清楚地解释了 set 里面可以存放什么东西,str 是可哈希的,所以可以放进 set 中,list 是不可哈希的,所以 set 中不能存放 list。那为什么 list 是不可哈希的呢,因为 list 是可变数据结构,如果一个 list 改变了,那它的哈希值必须跟着变。
上面代码的 set1 变量,虽然我们按顺序加入了 s1,s2,s3,但打印的结果确是无序的,这恰恰反映了 set 的无序特性。
下面看看唯一性:
set3 = {s1, s1, s1, s1, s2, s3}
print(set3) # {'abc', 'ghi', 'def'}
记住,不能哈希的不能存,同样哈希的只存一个。
Dictionaries
字典是一个十分有用的数据结构,它的存储方式是键值对。下面是创建,取值,添加等基本操作:
dic1 = {'a': 123, 'b': 456, 'c': 789}
print(dic1['a'] < dic1['b']) # True
dic1['d'] = 321
keys 函数返回所有 key 的集合,values 函数返回所有值的集合:
print('a' in dic1.keys()) # True
print(123 in dic1.values()) # True
同时访问 key 和 value 使用 items 函数:
for k, v in dic1.items():
print(k) if v > 456 else None # 'c'
下面我们再来看看 set,list 和 dictionary 共有的一些操作:
print(1 in [1, 2, 3]) # True
print("a" in {"a", "b", "c"}) # True
print("set" in {"list": [1, 2, 3], "set": {1, 2, 3}}) #True
in 操作可以用来检查某元素是否在容器里。
set 的检查操作比 list 的快,这是因为,检查一个元素是否在 list 中,需要遍历整个 list;而检查一个元素是否在 set 中,Python 的内部实现只执行了一个操作,a[hash(b)](a 为集合,b为要检查的元素),查看返回值是否为 None 来判断是否包含此元素。
最后来简单说下 list comprehension,列表解析。它的结构为 [ 表达式 + 环境 ]。
表达式:告诉 Python 你想对 list 中的每个元素做什么。
环境:告诉 Python 你的 list 是哪个 list
举个栗子:
[a for a in range(10)]
表达式:a,只是简单地把 list 中的元素拿出来,不做任何操作。
环境:a in range(10),a的取值范围是 range(10) 产生的 list。
set comprehension 的使用方式和 list 一致。
请关注公众号“读一读我”