目录| 上一节 (2.3 格式化) | 下一节 (2.5 Collections模块)html
Python 有三种序列数据类型。python
'Hello'
。字符串是字符序列[1, 4, 5]
。('GOOG', 100, 490.1)
。全部的序列都是有序的,由整数进行索引,而且具备长度。git
a = 'Hello' # String b = [1, 4, 5] # List c = ('GOOG', 100, 490.1) # Tuple # Indexed order a[0] # 'H' b[-1] # 5 c[1] # 100 # Length of sequence len(a) # 5 len(b) # 3 len(c) # 3
序列能够经过重复操做符 * 进行重复:s * n
。github
>>> a = 'Hello' >>> a * 3 'HelloHelloHello' >>> b = [1, 2, 3] >>> b * 2 [1, 2, 3, 1, 2, 3] >>>
相同类型的序列能够经过加号 + 进行拼接:s + t
。函数
>>> a = (1, 2, 3) >>> b = (4, 5) >>> a + b (1, 2, 3, 4, 5) >>> >>> c = [1, 5] >>> a + c Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can only concatenate tuple (not "list") to tuple
切片是指着从序列中提取子序列。切片的语法为 s[start:end]
。 start
和 end
是想要的子序列的索引。oop
a = [0,1,2,3,4,5,6,7,8] a[2:5] # [2,3,4] a[-5:] # [4,5,6,7,8] a[:3] # [0,1,2]
start
和 end
必须是整数。在列表上,切片能够被从新赋值和删除。编码
# Reassignment a = [0,1,2,3,4,5,6,7,8] a[2:4] = [10,11,12] # [0,1,10,11,12,4,5,6,7,8]
注意:从新赋值的切片不须要具备相同的长度。翻译
# Deletion a = [0,1,2,3,4,5,6,7,8] del a[2:4] # [0,1,4,5,6,7,8]
有一常见的函数用于把序列缩减为单个值。code
>>> s = [1, 2, 3, 4] >>> sum(s) 10 >>> min(s) 1 >>> max(s) 4 >>> t = ['Hello', 'World'] >>> max(t) 'World' >>>
可使用 for 循环对序列中的元素进行迭代。htm
>>> s = [1, 4, 9, 16] >>> for i in s: ... print(i) ... 1 4 9 16 >>>
在循环的每次迭代中,会获取一个新的项来处理。这个新的值会被放到迭代变量中。在此示例中,迭代变量为 x:
for x in s: # `x` is an iteration variable ...statements
在每次迭代中,迭代变量的先前值会被覆盖(若是有)。循环结束后,迭代变量保留最后一个值。
可使用 break
语句提早跳出循环。
for name in namelist: if name == 'Jake': break ... ... statements
当 break
语句执行时,它退出循环而且进入下一个语句。break
语句仅应用于最内部的循环。若是此循环在另外一个循环的内部,那么 break
不会中断外部循环。
要跳过一个元素而且进入到下一个,请使用 continue
语句。
for line in lines: if line == '\n': # Skip blank lines continue # More statements ...
若是当前项不重要或者是在处理时须要忽略,那么使用 continue
语句颇有用。
若是须要计数,请使用 range()
函数。
for i in range(100): # i = 0,1,...,99
range() 函数的语法是range([start,] end [,step])
。
for i in range(100): # i = 0,1,...,99 for j in range(10,20): # j = 10,11,..., 19 for k in range(10,50,2): # k = 10,12,...,48 # Notice how it counts in steps of 2, not 1.
start
是可选的 , 默认值是 0
。step
是可选的,默认值是 1
。range()
才计算值,实际上,它不存储大范围的数。enumerate
函数为迭代添加一个额外的计数值。
names = ['Elwood', 'Jake', 'Curtis'] for i, name in enumerate(names): # Loops with i = 0, name = 'Elwood' # i = 1, name = 'Jake' # i = 2, name = 'Curtis'
通常格式为enumerate(sequence [, start = 0])
,start
是可选的,一个很好的使用示例:读取文件时跟踪行数。
with open(filename) as f: for lineno, line in enumerate(f, start=1): ...
enumerate
能够当作如下语句的简写:
i = 0 for x in s: statements i += 1
使用 enumerate
函数能够减小输入,运行速度也稍快一些。
能够迭代多个变量:
points = [ (1, 4),(10, 40),(23, 14),(5, 6),(7, 8) ] for x, y in points: # Loops with x = 1, y = 4 # x = 10, y = 40 # x = 23, y = 14 # ...
当使用多个变量时,每一个元组被拆包为一组迭代变量。变量的数目必须与每一个元组中的项数匹配。
zip
函数采用多个序列,而且生成将它们组合在一块儿的迭代器。
columns = ['name', 'shares', 'price'] values = ['GOOG', 100, 490.1 ] pairs = zip(columns, values) # ('name','GOOG'), ('shares',100), ('price',490.1)
要得到结果,必须进行迭代。能够如先前所示的那样使用多个变量对元组进行拆包。
for column, value in pairs: ...
zip
函数的常见用法是建立用于构造字典的键值对。
d = dict(zip(columns, values))
尝试一些基本的计数示例:
>>> for n in range(10): # Count 0 ... 9 print(n, end=' ') 0 1 2 3 4 5 6 7 8 9 >>> for n in range(10,0,-1): # Count 10 ... 1 print(n, end=' ') 10 9 8 7 6 5 4 3 2 1 >>> for n in range(0,10,2): # Count 0, 2, ... 8 print(n, end=' ') 0 2 4 6 8 >>>
交互地试验一些序列缩减操做。
>>> data = [4, 9, 1, 25, 16, 100, 49] >>> min(data) 1 >>> max(data) 100 >>> sum(data) 204 >>>
尝试遍历数据。
>>> for x in data: print(x) 4 9 ... >>> for n, x in enumerate(data): print(n, x) 0 4 1 9 2 1 ... >>>
有时候,for
语句,len()
和 range()
函数被初学者用于一些可怕的代码片断中,这些代码看起来像来自于古老的 C 程序。
>>> for n in range(len(data)): print(data[n]) 4 9 1 ... >>>
不要那样作。阅读这些代码不只辣眼睛,并且内存效率低,运行慢。若是想要迭代数据,使用普通的for
循环便可。若是碰巧由于某些缘由须要使用索引,请使用 enumerate()
函数。
回想一下,Data/missing.csv
文件包含一个股票投资组合的数据,可是有一些行缺乏值。请使用 enumerate()
函数修改 pcost.py
程序,以便在遇到错误的输入时,打印带有警告信息的行号。
>>> cost = portfolio_cost('Data/missing.csv') Row 4: Couldn't convert: ['MSFT', '', '51.23'] Row 7: Couldn't convert: ['IBM', '', '70.44'] >>>
为此,须要修改部分代码。
... for rowno, row in enumerate(rows, start=1): try: ... except ValueError: print(f'Row {rowno}: Bad row: {row}')
在 Data/portfolio.csv
文件中,第一行包含列标题。在以前全部代码中,咱们把它丢弃了。
>>> f = open('Data/portfolio.csv') >>> rows = csv.reader(f) >>> headers = next(rows) >>> headers ['name', 'shares', 'price'] >>>
可是,若是标题要用于其它有用的事情呢?这就涉及到 zip()
函数了。首先,尝试把文件标题和数据行配对。
>>> row = next(rows) >>> row ['AA', '100', '32.20'] >>> list(zip(headers, row)) [ ('name', 'AA'), ('shares', '100'), ('price', '32.20') ] >>>
请注意 zip()
函数是如何把列标题与列值配对。在这里,咱们使用 list()
函数把结果转换为列表,以便查看。一般,zip()
函数建立一个必须由 for 循环使用的迭代器。
这种配对是构建字典的中间步骤。如今尝试:
>>> record = dict(zip(headers, row)) >>> record {'price': '32.20', 'name': 'AA', 'shares': '100'} >>>
在处理大量数据文件时,这种转换是最有用的技巧之一。例如,假设须要使 pcost.py
程序处理各类输入文件,可是不考虑名称,份额,价格所在列的编号。
修改 pcost.py
程序中的 portfolio_cost()
,使其看起来像这样:
# pcost.py def portfolio_cost(filename): ... for rowno, row in enumerate(rows, start=1): record = dict(zip(headers, row)) try: nshares = int(record['shares']) price = float(record['price']) total_cost += nshares * price # This catches errors in int() and float() conversions above except ValueError: print(f'Row {rowno}: Bad row: {row}') ...
如今,在一个彻底不一样的数据文件 Data/portfoliodate.csv
(以下所示)上尝试 portfolio_cost() 函数。
name,date,time,shares,price "AA","6/11/2007","9:50am",100,32.20 "IBM","5/13/2007","4:20pm",50,91.10 "CAT","9/23/2006","1:30pm",150,83.44 "MSFT","5/17/2007","10:30am",200,51.23 "GE","2/1/2006","10:45am",95,40.37 "MSFT","10/31/2006","12:05pm",50,65.10 "IBM","7/9/2006","3:15pm",100,70.44
>>> portfolio_cost('Data/portfoliodate.csv') 44671.15 >>>
若是操做正确,会发现程序仍然可以正常运行,即便数据文件的列格式与以前的彻底不一样,这很酷!
此处所作的更改是微妙的,可是却意义重大。新版的 portfolio_cost()
能够读取任何 CSV 文件,并从中选择须要的值,而不是硬编码去读取单个固定文件格式。只要文件有必要的列,代码就能正常运行。
修改在 2.3 节编写的 report.py
程序,以便可以使用相同的技术挑选出列标题。
尝试以 Data/portfoliodate.csv
文件做为输入,运行 report.py
程序,并观察是否生成和以前同样的答案。
字典将键映射到值。例如,股票价格字典。
>>> prices = { 'GOOG' : 490.1, 'AA' : 23.45, 'IBM' : 91.1, 'MSFT' : 34.23 } >>>
若是使用字典的 items()
方法,那么能够获取到键值对 (key,value)
:
>>> prices.items() dict_items([('GOOG', 490.1), ('AA', 23.45), ('IBM', 91.1), ('MSFT', 34.23)]) >>>
可是,若是想要获取 (value, key)
键值对列表呢?
提示:使用 zip()
函数。
>>> pricelist = list(zip(prices.values(),prices.keys())) >>> pricelist [(490.1, 'GOOG'), (23.45, 'AA'), (91.1, 'IBM'), (34.23, 'MSFT')] >>>
为何这样操做?首先,这容许对字典数据执行确切类型的数据处理。
>>> min(pricelist) (23.45, 'AA') >>> max(pricelist) (490.1, 'GOOG') >>> sorted(pricelist) [(23.45, 'AA'), (34.23, 'MSFT'), (91.1, 'IBM'), (490.1, 'GOOG')] >>>
其次,这也说明了元组的一个重要特征,当在比较中使用元组时,从第一项开始,逐元素进行比较,相似于字符串中字符与字符逐个比较。
zip()
函数常常应用于须要从不一样的地方把数据进行配对。例如,为了使用已命名的值构建字典,将列名和列值进行配对。
请注意,zip()
函数不限于一对。例如,可使用任意数量的列表做为输入。
>>> a = [1, 2, 3, 4] >>> b = ['w', 'x', 'y', 'z'] >>> c = [0.2, 0.4, 0.6, 0.8] >>> list(zip(a, b, c)) [(1, 'w', 0.2), (2, 'x', 0.4), (3, 'y', 0.6), (4, 'z', 0.8))] >>>
另外,请注意,一旦最短的输入序列耗尽,zip()
函数将会中止。
>>> a = [1, 2, 3, 4, 5, 6] >>> b = ['x', 'y', 'z'] >>> list(zip(a,b)) [(1, 'x'), (2, 'y'), (3, 'z')] >>>