Python3.7官方向导翻译之python数据结构

关于列表的更多信息

列表数据类型有很多方法

这里写图片描述

fruits = ['oranges', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
fruits.count('apple')
2
fruits.index('banana')
3
fruits.index('banana', 4) #Find next banana starting a position 4
6
fruits.reverse()
fruits
['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'oranges']
fruits.append('grape')
fruits
['banana',
 'apple',
 'kiwi',
 'banana',
 'pear',
 'apple',
 'oranges',
 'grape',
 'grape']
fruits.sort()
fruits
['apple',
 'apple',
 'banana',
 'banana',
 'grape',
 'grape',
 'kiwi',
 'oranges',
 'pear']
fruits.pop()
'pear'

您可能已经注意到,插入,移除或排序只修改列表的方法没有返回值 - 它们返回默认的None。 [1]这是Python中所有可变数据结构的设计原则。

使用列表做为栈

列表方法使得使用列表作为堆栈非常容易,其中添加的最后一个元素是检索到的第一个元素(“后进先出”)。 要将项目添加到堆栈的顶部,请使用append()。 要从堆栈顶部检索一个项目,请使用pop()而不显示索引。 例如

stack = [3, 4, 5]
stack.append(6)
stack.append(7)
stack
[3, 4, 5, 6, 7]
stack.pop()
7
stack.pop()
6
stack
[3, 4, 5]

使用列表作为队列

也可以使用列表作为队列,其中添加的第一个元素是检索到的第一个元素(“先入先出”);

要实现一个队列,请使用collections.deque,它的设计目的是快速追加并从两端弹出。 例如:

from collections import deque
queue = deque(['Eric', 'John', 'Michael'])
queue.append('Terry')  #Terry arrives
queue.append('Graham') #Graham arrives
queue.popleft()        #The first to arrive now leaves
'Eric'

列表生成式List Comprehensions

列表解析提供了一个简洁的方式来创建列表。 常见的应用是创建新的列表,其中每个元素是应用于另一个序列的每个成员或迭代的某些操作的结果,或者创建满足特定条件的那些元素的子序列

squares = []
for x in range(10):
    squares.append(x**2)

squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

请注意,这会创建(或覆盖)循环完成后仍然存在的名为x的变量。 我们可以使用以下方法计算无任何副作用的列表:

squares = list(map(lambda x: x**2, range(10)))
squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

下面的这种方式更简洁和可读,推荐!

squares = [x**2 for x in range(10)]
squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

列表生成式由括号组成,括号中包含一个表达式,后面跟着for子句,然后是零个或多个for子句或if子句。 结果将成为一个新的列表。

[(x, y) for x in [1, 2, 3] for y in [3, 1,4] if x!= y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
#it is equivalent to following code
combs = []
for x in [1, 2, 3]:
    for y in [3, 1, 4]:
        if x != y:
            combs.append((x,y))

combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

请注意这两个片段中for和if语句的顺序是如何相同的

如果表达式是一个元组,如(x, y),必须要加上括号

vec = [-4, -2, 0, 2, 4]
#create a new list with the values doubled
[x*2 for x in vec]
[-8, -4, 0, 4, 8]
#filter the list to exclude negative numbers
[x for x in vec if x >= 0]
[0, 2, 4]
#apply a function to all the elements
[abs(x) for x in vec]
[4, 2, 0, 2, 4]
#call a method on each element
freshfruit = [' banana', ' loganberry ', 'passion fruit ']
[weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']
# create a list of 2-tuples like(number, square)
[(x, x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
# the tuple must be parenthesized, otherwise an error is raised
[x, x**2 for x in range(x)]
  File "<ipython-input-38-96d88748f64d>", line 2
    [x, x**2 for x in range(x)]
               ^
SyntaxError: invalid syntax
# flatten a list using a listcomp with two 'for'
vec = [[1, 2, 3],[4,5,6], [7,8,9]]
[num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

列表生成式可以包含复数表达式和嵌套函数

from math import pi
[str(round(pi, i)) for i in range(1, 6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']

嵌套列表生成式

列表生成式中的初始表达式可以是任意的表达式,包括另一个列表生成式。

考虑下面的3×4矩阵,由3个长度为4的列表组成的列表

matrix = [[1, 2, 3, 4], 
         [5, 6, 7, 8],
         [9, 10, 11, 12]]

下面的列表生成式会转置行和列

[[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

在现实世界中,您应该更喜欢内置函数来处理复杂的流程语句。 对于这个用例,zip()函数可以做很好的工作

list(zip(*matrix))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

del语句

有一种方法可以从列表中删除项目,只要它的索引而不是其值:del语句。 这不同于返回值的pop()方法。 del语句也可用于从列表中删除切片或清除整个列表(我们之前通过将空列表分配给切片)。

a = [-1, 1, 66.25, 333, 333, 1234.5]
del a[0]
del a[2:4]
a
[1, 66.25, 1234.5]
del a[:]
a
[]
# del can also use to delete entire variables
del a 

以后引用这个名字是一个错误(至少直到另一个值被分配给它)。 我们稍后会发现del的其他用途。

元组和序列tuples and sequences

我们看到列表和字符串有许多共同的属性,如索引和切片操作。 它们是序列数据类型的两个示例(请参见序列类型 - 列表,元组,范围)。 由于Python是一种不断发展的语言,因此可能会添加其他序列数据类型。 这里有另一种标准的序列数据类型:元组。

元组有一些了被逗号分开的值构成

t = 12345, 54321, 'hello'
t[0]
12345
t
(12345, 54321, 'hello')
# tuples may be nested:
u = t, (1, 2, 3, 4, 5)
u
((12345, 54321, 'hello'), (1, 2, 3, 4, 5))
# Tuples are immutable:
t[0] = 88888
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-53-9e19cce22619> in <module>()
      1 # Tuples are immutable:
----> 2 t[0] = 88888


TypeError: 'tuple' object does not support item assignment
#but they can contain mutable objects:
v = ([1, 2, 3], [3, 2, 1])
v
([1, 2, 3], [3, 2, 1])

正如你所看到的,在输出中,元组总是被括在圆括号中,以便嵌套元组被正确解释; 它们可能带有或不带括号的圆括号输入,尽管通常括号是必要的(如果元组是更大表达式的一部分)。 无法分配给元组的各个项目,但是可以创建包含可变对象(例如列表)的元组。

虽然元组可能看起来与列表类似,但它们通常用于不同的情况和不同的目的。 元组是不可变的,并且通常包含通过解包(本节后面的内容)或索引(甚至在命名的情况下通过属性)访问的异构元素序列。 列表是可变的,它们的元素通常是同类的,并且通过遍历列表来访问。

一个特殊的问题是构造包含0或1项的元组:语法有一些额外的怪癖以适应这些。 空元组由空括号构成; 带有一个项目的元组是通过跟随带有逗号的值构建的(这不足以将单个值括在圆括号中)。 丑陋,但有效。 例如:

empty = ()
singleton = 'hello', #<--note trailing comma
len(empty)
0
len(singleton)
1
singleton
('hello',)

语句 t=12345, 54321, ‘hello!’ 是元组打包的一个例子(packing):值12345,54321和’hello!’ 在一个元组中包装在一起。 反向操作也是可能的:

x, y, z = t

这被称为序列拆包,适用于在右侧的任何序列。 序列解包要求等号左侧的变量数量与序列中的元素数量相同。 请注意,多重赋值实际上只是元组打包和序列解包的组合。

集合sets

Python还包含一组数据类型。 一个集合是一个没有重复元素的无序集合。 基本用途包括成员资格测试和消除重复条目。 集合对象还支持像联合,交集,差异和对称差异等数学运算。

大括号或set()函数可用于创建集合。 注意:要创建一个空集,必须使用set(),而不是{}; 后者创建一个空字典,我们将在下一节讨论一个数据结构

basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
print(basket)
{'apple', 'banana', 'orange', 'pear'}
'orange' in basket
True
a = set('abracadabra')
b = set('alacazam')
a
{'a', 'b', 'c', 'd', 'r'}
a - b #letters in a but not in b
{'b', 'd', 'r'}
a | b #letters in a or b or both
{'a', 'b', 'c', 'd', 'l', 'm', 'r', 'z'}
a & b # letters in both a and b
{'a', 'c'}
a ^ b # letters in a or b but not both
{'b', 'd', 'l', 'm', 'r', 'z'}

集合生成式也支持

a = {x for x in 'abracadabra' if x not in 'abc'}
a
{'d', 'r'}

词典 dictionaries

Python中内置的另一个有用的数据类型是字典(参见映射类型 - 字典)。 字典有时在其他语言中被称为“联想记忆”或“联想阵列”。 与由一系列数字索引的序列不同,字典由键索引,可以是任何不可变类型; 字符串和数字始终可以是键。
如果元组只包含字符串,数字或元组,则可以用作键; 如果元组直接或间接包含任何可变对象,则不能将其用作关键字。
您不能使用列表作为关键字,因为可以使用索引分配,切片分配或像append()和extend()这样的方法来修改列表。

最好将字典视为一组无序的键:值对,并要求键是唯一的(在一个字典中)。 一对大括号创建一个空字典:{}。 在大括号中放置一个以逗号分隔的键:值对列表,可将初始键:值对添加到字典中; 这也是字典写在输出上的方式。

字典上的主要操作是用某个键存储一个值,并提取给定键的值。 也可以使用del删除一个key:value对。 如果您使用已在使用的键进行存储,则与该键关联的旧值将被遗忘。 使用不存在的键提取值是错误的。

在字典上执行列表(d.keys())可以以任意顺序返回字典中使用的所有键的列表(如果您想对其进行排序,则只需使用sorted(d.keys()))。要检查字典中是否有单个键,请使用in关键字。

tel = {'jack': 4098, 'sape': 4139}
tel['guido'] = 4127
tel
{'guido': 4127, 'jack': 4098, 'sape': 4139}
tel['jack']
4098
tel['irv'] = 4127
tel
{'guido': 4127, 'irv': 4127, 'jack': 4098, 'sape': 4139}
list(tel.keys())
['sape', 'guido', 'irv', 'jack']
sorted(tel.keys())
['guido', 'irv', 'jack', 'sape']
'guido' in tel
True

dict()构造函数直接从键值对的序列构建字典:

dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'guido': 4127, 'jack': 4098, 'sape': 4139}

另外,可以使用字典生成式(dict comprehensions)从任意键和值表达式创建词典

{x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}

当键是简单字符串时,使用关键字参数指定对有时会更容易:

dict(sape=4139, guido=4127, jack=4098)
{'guido': 4127, 'jack': 4098, 'sape': 4139}

循环技巧

在遍历字典时,可以使用items()方法同时检索键和相应的值。

knights = {'gallahad': 'the pure', 'robin': 'the brave'}
for k, v in knights.items():
    print(k, v)
robin the brave
gallahad the pure

在循环一个序列时,可以使用enumerate()函数同时检索位置索引和相应的值。

for i, v in enumerate(['tic', 'tac', 'toe']):
    print(i, v)
0 tic
1 tac
2 toe

要同时循环两个或更多个序列,可以将这些条目与zip()函数配对

questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for q, a in zip(questions, answers):
    print('what is your {0}? It is {1}.'.format(q, a))
what is your name? It is lancelot.
what is your quest? It is the holy grail.
what is your favorite color? It is blue.

要以反向循环序列,首先以正向指定序列,然后调用reversed()函数。

for i in reversed(range(1, 10, 2)):
    print(i)
9
7
5
3
1

要以排序顺序遍历序列,请使用sorted()函数,该函数返回一个新的排序列表,同时保持源不变。

basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for f in sorted(set(basket)):
    print(f)
apple
banana
orange
pear

在循环列表时,有时候很容易改变列表; 但是,创建新列表通常更简单,更安全。

import math
raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
filtered_data = []
for value in raw_data:
    if not math.isnan(value):
        filtered_data.append(value)

filtered_data
[56.2, 51.7, 55.3, 52.5, 47.8]

关于条件conditions的更多信息

比较运算符innot in检查一个值是否出现在序列中。操作符isis not比较是否两个对象是同一个对象,这只对列表等可变对象很重要。所有的比较操作符拥有相同的优先级,它们的等级比数值操作符低。
比较可以链接。 例如,a < b == c测试a是否小于b,而且b等于c。

比较可以通过布尔操作符and和or组合,比较结果或者任何布尔表达式可以使用not操作符取反。它们相比与比较操作符的优先级低,在他们之间,not具有最高的优先级,or具有最低优先级,所以A and not B or C 等价于(A and (not B)) or C.与以往一样,可以使用括号来表示期望的组成。

布尔运算符and 和 or 是所谓的短路运算符:它们的参数从左到右进行判断,并在结果确定后立即停止判断。 例如,如果A和C为真,但B为假,则A and B and C不会判断evaluate表达式C.当用作通用值而不是布尔值时,短路运算符的返回值是最后一个判断。

string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
non_null = string1 or string2 or string3
non_null
'Trondheim'

请注意,在Python中,与C不同,赋值不能在表达式内发生。 C程序员可能会为此感到抱怨,但它避免了C程序中遇到的一类常见问题:打算==时在表达式中输入=。

比较序列和其他类型

序列对象可以与具有相同序列类型的其他对象进行比较。 比较使用的是词典排序:首先比较前两项,如果它们不同,则确定比较的结果; 如果它们相等,则比较下两个项目,等等,直到任何一个序列被耗尽。 如果要比较的两个项目本身是同一类型的序列,则字典对比将递归执行。 如果两个序列的所有项目比较相等,则序列被认为是相等的。 如果一个序列是另一个序列的初始子序列,则较短的序列是较小(较小)的序列。 字符串的字典排序使用Unicode代码点号来排列单个字符。 一些相同类型序列之间比较的例子

(1, 2, 3) < (1, 2, 4)
True
[1, 2, 3] < [1, 2, 4]
True
'Abc' < 'C' < 'Pascal' < 'python'
True
(1, 2, 3, 4) < (1, 2, 4)
True
(1, 2) < (1,2, -1)
True
(1, 2, 3) == (1.0, 2.0, 3.0)
True
(1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4)
True

请注意,使用<或>比较不同类型的对象是合法的(legal),只要对象具有适当的比较方法即可。 例如,混合数字类型根据它们的数值进行比较,所以0等于0.0等。否则,解释器将提出TypeError异常,而不是提供任意排序。

猜你喜欢

转载自blog.csdn.net/u010132497/article/details/80670898
今日推荐