溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Python數(shù)據(jù)類(lèi)型之列表和元組的方法實(shí)例詳解

發(fā)布時(shí)間:2020-10-25 10:52:42 來(lái)源:腳本之家 閱讀:300 作者:mrr 欄目:開(kāi)發(fā)技術(shù)

引言

我們前面的文章介紹了數(shù)字和字符串,比如我計(jì)算今天一天的開(kāi)銷(xiāo)花了多少錢(qián)我可以用數(shù)字來(lái)表示,如果是整形用 int ,如果是小數(shù)用 float ,如果你想記錄某件東西花了多少錢(qián),應(yīng)該使用 str 字符串型,如果你想記錄表示所有開(kāi)銷(xiāo)的物品名稱(chēng),你應(yīng)該用什么表示呢?

可能有人會(huì)想到我可以用一個(gè)較長(zhǎng)的字符串表示,把所有開(kāi)銷(xiāo)物品名稱(chēng)寫(xiě)進(jìn)去,但是問(wèn)題來(lái)了,如果你發(fā)現(xiàn)你記錄錯(cuò)誤了,想刪除掉某件物品的名稱(chēng),那你是不是要在這個(gè)長(zhǎng)字符串中去查找到,然后刪除,這樣雖然可行,那是不是比較麻煩呢。

這種情況下,你是不是需要Python給我們提供一種新的數(shù)據(jù)結(jié)構(gòu),可以存儲(chǔ)很多個(gè)字符串,能讓我們方便的添加修改和刪除,就完美了。

列表(list)同字符串一樣都是有序的,因?yàn)樗麄兌伎梢酝ㄟ^(guò)切片和索引進(jìn)行數(shù)據(jù)訪(fǎng)問(wèn),列表是可變(mutable)的,你可以修改、更新和刪除。

列表是一組有序項(xiàng)目的集合 ,可變的數(shù)據(jù)類(lèi)型可 進(jìn)行增刪改查 ; 列表中可以包含Python中任何數(shù)據(jù)類(lèi)型和對(duì)象,也可包含另一個(gè)列表 可任意組合嵌套 列表是以方括號(hào) [] 包圍的數(shù)據(jù)集合,不同成員以 , 分隔,列表可通過(guò)序號(hào)訪(fǎng)問(wèn)其中成員。

列表可以裝入Python中所有的對(duì)象,看下面的例子就知道:

all_list = [
 'nock',  # 字符串
 1,  # 整數(shù)
 2.0,  # 浮點(diǎn)數(shù)
 print('hello'), # 函數(shù)
 True,  # 布爾值
 None,  # 空值
 [1, 2],  # 列表
 (3,4),  # 元組
 {'name': 'nock', 'age': 18} # 字典
]

列表的定義和創(chuàng)建

定義: [] 內(nèi)以逗號(hào)分隔,按照索引,存放各種數(shù)據(jù)類(lèi)型,每個(gè)位置代表一個(gè)元素

列表的創(chuàng)建:

第一種:

fruit = ['pineapple', 'pear']

第二種:

fruit = list(['pineapple', 'pear'])

其他數(shù)據(jù)類(lèi)型轉(zhuǎn)為列表:

1、把一個(gè)字符串轉(zhuǎn)化成列表

>>> alphabet = 'abcd'
>>> alphabet_list = list(alphabet)
>>> alphabet_list
['a', 'b', 'c', 'd']

list在把字符串轉(zhuǎn)換成列表的時(shí)候,會(huì)把字符串用for循環(huán)迭代一下,然后把每個(gè)值當(dāng)作list的一個(gè)元素。

2、把元組轉(zhuǎn)換成列表

>>> jobs = ('pm', 'dev', 'qa', 'ops')
>>> jobs_list = list(jobs)
>>> type(jobs_list)
<type 'list'>
>>> jobs_list
['pm', 'dev', 'qa', 'ops']

3、把字典轉(zhuǎn)成列表

>>> age = {'tom': 15, 'jim': 18, 'jerry': 20}
>>> age_list = list(age)
>>> type(age_list)
<type 'list'>
>>> age_list
['jim', 'jerry', 'tom']
>>> values_list = list(age.values())
>>> values_list
[18, 20, 15]

list在把字典轉(zhuǎn)換成列表的時(shí)候,默認(rèn)循環(huán)的是字典的key,所以會(huì)把key當(dāng)作列表的元素;如果指定循環(huán)的是values,那么就會(huì)把values當(dāng)作列表的元素。

列表的特點(diǎn)和常用方法

特征:

  1. 多值: 可存放多個(gè)值
  2. 有序: 按照從左到右的順序定義列表元素,下標(biāo)從0開(kāi)始順序訪(fǎng)問(wèn)

Python數(shù)據(jù)類(lèi)型之列表和元組的方法實(shí)例詳解

3.可變: 可修改指定索引位置對(duì)應(yīng)的值

列表的增刪改查:

增加操作:

# 增 插入 可插入到任何位置
>>> fruit = ['pineapple', 'pear']
>>> fruit.insert(1, 'grape')
>>> fruit
['pineapple', 'grape', 'pear']

Python數(shù)據(jù)類(lèi)型之列表和元組的方法實(shí)例詳解 

在使用 insert 方法的時(shí)候,必須要指定列表中要插入的新元素的位置,插入元素的實(shí)際位置是在 指定位置元素的前面的

位置 ,如果指定插入的位置在列表中不存在,實(shí)際上也就是超出指定列表的長(zhǎng)度,程序運(yùn)行不會(huì)報(bào)錯(cuò),但是這個(gè)元素一定會(huì)被放到這個(gè)列表的最后位置。

>>> fruit = ['pineapple', 'pear']
>>> fruit.insert(4, 'grape')
>>> fruit
['pineapple', 'pear', 'grape']
# 增 append方法 數(shù)據(jù)會(huì)追加到尾部
>>> fruit = ['pineapple', 'pear']
>>> fruit.append('grape')
>>> fruit
['pineapple', 'pear', 'grape']

Python數(shù)據(jù)類(lèi)型之列表和元組的方法實(shí)例詳解

# 合并 extend 把一個(gè)列表的值合并到當(dāng)前一個(gè)列表中
>>> fruit_one = ['banana', 'apple', 'orange']
>>> fruit_two = ['pineapple', 'grape', 'pear']
>>> fruit_one.extend(fruit_two)
>>> fruit_one
['banana', 'apple', 'orange', 'pineapple', 'grape', 'pear']

Python數(shù)據(jù)類(lèi)型之列表和元組的方法實(shí)例詳解

刪除操作:

# del 直接刪除
>>> jobs = ['PM', 'UI', 'QA', 'OPS']
>>> del jobs[0]
>>> jobs
['UI', 'QA', 'OPS']

# remove 根據(jù)remove方法,
>>> jobs = ['PM', 'UI', 'QA', 'OPS']
>>> jobs.remove('PM')
>>> jobs
['UI', 'QA', 'OPS']

# pop 默認(rèn)刪除列表最后一個(gè)元素
>>> jobs = ['PM', 'UI', 'QA', 'OPS']
>>> jobs.pop() # pop方法,默認(rèn)刪除最后一個(gè),返回刪除元素
'OPS'
>>> jobs
['PM', 'UI', 'QA']
>>> help(jobs.pop)
Help on built-in function pop:

pop(...) method of builtins.list instance
 L.pop([index]) -> item -- remove and return item at index (default last).
 Raises IndexError if list is empty or index is out of range.
>>> jobs.pop(1) # pop還可以指定元素下標(biāo),指定刪除
'UI'
>>> jobs
['PM', 'QA']

# clear 方法清空一個(gè)列表
>>> jobs = ['PM', 'UI', 'QA', 'OPS']
>>> jobs.clear()
>>> jobs
[]

remove方法刪除一個(gè)元素,必須是在列表中的,否則會(huì)報(bào)錯(cuò),del利用下標(biāo)來(lái)刪除元素,pop默認(rèn)刪除最后一個(gè)元素,也可以指定元素下標(biāo)來(lái)刪除。

修改操作:

>>> jobs = ['PM', 'UI', 'UE', 'OPS', 'DBA', 'DEV']
>>> jobs[2] = 'QA' # 把下標(biāo)為2的元素替換成QA,根據(jù)下標(biāo)然后給元素重新賦值
>>> jobs
['PM', 'UI', 'QA', 'OPS', 'DBA', 'DEV']
>>> jobs[-2] = 'Sales' # 把下標(biāo)為12的元素替換成Sales,根據(jù)下標(biāo)然后給元素重新賦值
>>> jobs
['PM', 'UI', 'QA', 'OPS', 'Sales', 'DEV']

查詢(xún)操作:

>>> jobs = ['PM', 'UI', 'UE', 'OPS', 'DBA', 'DEV']
>>> jobs[1]
'UI'
>>> jobs[2]
'UE'
>>> jobs[4]
'DBA'
>>> jobs[-2] # 還可以倒數(shù)著來(lái),不過(guò)下標(biāo)從-1開(kāi)始
'DBA'

列表索引:

>>> jobs = ['PM', 'UI', 'OPS', 'UE', 'OPS', 'DBA', 'DEV', 'UE']
>>> jobs.index('OPS')
2
>>> jobs.index('UE')
3
>>> jobs.index('xx')
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
ValueError: 'xx' is not in list
>>> if 'OPS' in jobs:
 ... print(jobs.index('OPS'))
 ... 
 2

索引下標(biāo),只會(huì)返回第一個(gè)元素的下標(biāo),如果元素不在列表中,會(huì)報(bào)錯(cuò),我們可以利用 in 這個(gè)關(guān)鍵之來(lái)判斷元素是否在列表中。

列表切片:

>>> jobs = ['PM', 'UI', 'UE', 'OPS', 'DBA', 'DEV']
>>> jobs[1:4] # 取下標(biāo)從1到4的元素,但是不包括4,列表切片的特征就是左開(kāi)右閉,也就是左取右棄。
['UI', 'UE', 'OPS']
>>> jobs[1:-1] # 取下標(biāo)為1到-1的元素,不包括-1,也就是最后一個(gè)元素不會(huì)被取出來(lái)。
['UI', 'UE', 'OPS', 'DBA']
>>> jobs[:] # 這個(gè)在切片符左右沒(méi)有下標(biāo)限制,所以就是代表全取
['PM', 'UI', 'UE', 'OPS', 'DBA', 'DEV']
>>> jobs[::] # 效果和上面一樣,但是你會(huì)發(fā)現(xiàn)有兩切片符,這是因?yàn)榍衅幸粋€(gè)步長(zhǎng)的概念
['PM', 'UI', 'UE', 'OPS', 'DBA', 'DEV']
>>> jobs[0:3] # 取下標(biāo)0到3的元素,但不包括3
['PM', 'UI', 'UE']
>>> jobs[:3] # 和上面效果一樣
['PM', 'UI', 'UE']
>>> jobs[3:] # 從下標(biāo)3開(kāi)始,到最后一個(gè)元素
['OPS', 'DBA', 'DEV']
>>> jobs[3:-1] # 從下標(biāo)3開(kāi)始,到最后一個(gè)元素,但是不包括最后一個(gè)元素
['OPS', 'DBA']
>>> jobs[0::2] # 從下標(biāo)0開(kāi)始,按照2個(gè)步長(zhǎng)取值
['PM', 'UE', 'DBA']
>>> jobs[::2] # 和上面效果一樣
['PM', 'UE', 'DBA']

利用下標(biāo)取出的一個(gè)單獨(dú)元素是str類(lèi)型,而利用分片取出的是一個(gè)list類(lèi)型。

列表元素統(tǒng)計(jì):

>>> jobs = ['PM', 'UI', 'OPS', 'UE', 'OPS', 'DBA', 'DEV']
>>> jobs.count('OPS') # 因?yàn)榱斜硎怯行虻囊环N數(shù)據(jù)類(lèi)型,所以它的元素是可以重疊的,所以有元素統(tǒng)計(jì)。
2

列表排序和翻轉(zhuǎn):

>>> jobs = ['PM', 'UI', 'OPS', 'UE', 'OPS', 'DBA', 'DEV', 1, 2, 3]
>>> jobs.sort()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()  # Python3.0里不同數(shù)據(jù)類(lèi)型不能放在一起排序了,擦
>>> jobs[-1] = '3'
>>> jobs[-2] = '2'
>>> jobs[-3] = '1'
>>> jobs
['DBA', 'DEV', 'OPS', 'OPS', 'PM', 'UE', 'UI', '1', '2', '3']
>>> jobs.sort()
>>> jobs
['1', '2', '3', 'DBA', 'DEV', 'OPS', 'OPS', 'PM', 'UE', 'UI']
>>> jobs.append('#')
>>> jobs.append('&')
>>> jobs.sort()
>>> jobs
['#', '&', '1', '2', '3', 'DBA', 'DEV', 'OPS', 'OPS', 'PM', 'UE', 'UI'] # 可以看出排序的順序 特殊字符->數(shù)字->字母 這么一個(gè)優(yōu)先級(jí)
>>> jobs.reverse() # 翻轉(zhuǎn)最后到最前面
>>> jobs
['UI', 'UE', 'PM', 'OPS', 'OPS', 'DEV', 'DBA', '3', '2', '1', '&', '#']

sort() 方法會(huì)修改原列表,而不是創(chuàng)建一個(gè)新的有序列表, reverse() 也會(huì)修改原列表,但是你希望排序,但是又不希望修改原列表,你只能利用Python中一個(gè)名為 sorted() 的內(nèi)置函數(shù)來(lái)操作:

>>> jobs = ['UI', 'UE', 'PM', 'OPS', 'OPS', 'DEV', 'DBA', '3', '2', '1', '&', '#']
>>> newlist = sorted(jobs)
>>> jobs
['UI', 'UE', 'PM', 'OPS', 'OPS', 'DEV', 'DBA', '3', '2', '1', '&', '#']
>>> newlist
['#', '&', '1', '2', '3', 'DBA', 'DEV', 'OPS', 'OPS', 'PM', 'UE', 'UI']

列表拷貝:

>>> jobs
['PM', 'UI', 'UE', 'OPS', 'DBA', 'DEV']
>>> jobs_copy = jobs.copy() # 復(fù)制一份jobs列表
>>> jobs_copy
['PM', 'UI', 'UE', 'OPS', 'DBA', 'DEV']
>>> jobs = ['PM', 'UI', 'UE', 'OPS', ['DBA', 'QA', 'DEV']] # 嵌入式列表
>>> jobs_copy2 = jobs.copy()
>>> jobs_copy2
['PM', 'UI', 'UE', 'OPS', ['DBA', 'QA', 'DEV']]
>>> jobs[0] = 'HR' # 改變小標(biāo)為0的元素
>>> jobs
['HR', 'UI', 'UE', 'OPS', ['DBA', 'QA', 'DEV']] # 改變了
>>> jobs_copy2
['PM', 'UI', 'UE', 'OPS', ['DBA', 'QA', 'DEV']] # 沒(méi)變
>>> jobs[-1][0] = 'Sales' # 改變內(nèi)嵌列表的下標(biāo)為0的元素
>>> jobs
['HR', 'UI', 'UE', 'OPS', ['Sales', 'QA', 'DEV']] # 改變了
>>> jobs_copy2
['PM', 'UI', 'UE', 'OPS', ['Sales', 'QA', 'DEV']] # 改變了

從上面可以看出列表的copy方法是一個(gè)淺copy的栗子,只會(huì)拷貝第一次,而多層嵌入的話(huà),會(huì)隨著源列表的變化為變化,關(guān)于深拷貝和淺拷貝后面詳細(xì)介紹。

列表所有的方法如下:

class list(object):
 """
 list() -> new empty list
 list(iterable) -> new list initialized from iterable's items
 """
 def append(self, p_object): # real signature unknown; restored from __doc__
 """ L.append(object) -> None -- append object to end """
 pass

 def clear(self): # real signature unknown; restored from __doc__
 """ L.clear() -> None -- remove all items from L """
 pass

 def copy(self): # real signature unknown; restored from __doc__
 """ L.copy() -> list -- a shallow copy of L """
 return []

 def count(self, value): # real signature unknown; restored from __doc__
 """ L.count(value) -> integer -- return number of occurrences of value """
 return 0

 def extend(self, iterable): # real signature unknown; restored from __doc__
 """ L.extend(iterable) -> None -- extend list by appending elements from the iterable """
 pass

 def index(self, value, start=None, stop=None): # real signature unknown; restored from __doc__
 """
 L.index(value, [start, [stop]]) -> integer -- return first index of value.
 Raises ValueError if the value is not present.
 """
 return 0

 def insert(self, index, p_object): # real signature unknown; restored from __doc__
 """ L.insert(index, object) -- insert object before index """
 pass

 def pop(self, index=None): # real signature unknown; restored from __doc__
 """
 L.pop([index]) -> item -- remove and return item at index (default last).
 Raises IndexError if list is empty or index is out of range.
 """
 pass

 def remove(self, value): # real signature unknown; restored from __doc__
 """
 L.remove(value) -> None -- remove first occurrence of value.
 Raises ValueError if the value is not present.
 """
 pass

 def reverse(self): # real signature unknown; restored from __doc__
 """ L.reverse() -- reverse *IN PLACE* """
 pass

 def sort(self, key=None, reverse=False): # real signature unknown; restored from __doc__
 """ L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE* """
 pass

列表推導(dǎo)式:

列表推導(dǎo)式(又稱(chēng)列表解析式)提供了一種簡(jiǎn)明扼要的方法來(lái)創(chuàng)建列表,它的語(yǔ)法簡(jiǎn)單,很有實(shí)用價(jià)值。

它的結(jié)構(gòu)是在一個(gè)中括號(hào)里包含一個(gè)表達(dá)式,然后是一個(gè)for語(yǔ)句,然后是0個(gè)或多個(gè)for或者if語(yǔ)句。那個(gè)表達(dá)式可以是任意的,意思是你可以在列表中放入任意類(lèi)型的對(duì)象。返回結(jié)果將是一個(gè)新的列表,在這個(gè)以if和for語(yǔ)句為上下文的表達(dá)式運(yùn)行完成之后產(chǎn)生。

列表解析的一般形式:

[expr for item in itratorable]
L = [x**2 for x in range(10)]
print(L)
Result:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

列表解析返回的是列表, 列表的內(nèi)容是表達(dá)式執(zhí)行的結(jié)果.

[expr for item in iterable if cond]
[x ** 0.5 for x in range(10) if x % 2 == 0]
[0.0, 1.4142135623730951, 2.0, 2.449489742783178, 2.8284271247461903]
[expr for item in iterable if cond1 if cond2]
[x for x in range(10) if x % 2 == 0 if x > 1]
[2, 4, 6, 8]
[expr for item1 in iterable1 for item2 in iterable2]
[(x, y) for x in range(10) for y in range(10) if (x+y) %2 == 0]

列表解析用于對(duì)可迭代對(duì)象做過(guò)濾和轉(zhuǎn)換,返回值是列表.

特性一:代碼變短,可讀性更好

Python數(shù)據(jù)類(lèi)型之列表和元組的方法實(shí)例詳解

從上圖代碼示例中我們明顯可以看出,列表推導(dǎo)式相比常規(guī)方法,寫(xiě)出來(lái)的代碼更加符合pythonic,更加簡(jiǎn)短,可讀性更好。

有些人甚至更喜歡使用它而不是filter函數(shù)生成列表,但是當(dāng)你使用列表推導(dǎo)式效果會(huì)更加,列表推導(dǎo)式在有些情況下超贊,特別是當(dāng)你需要使用for循環(huán)來(lái)生成一個(gè)新列表.

特征二:推導(dǎo)式速度更快

#!/usr/bin/env python3
# author: nock
import timeit

lst = list(range(10))
# 常規(guī)方法
def origin(lst):
 plus_one = []
 for i in lst:
 plus_one.append(i + 1)
 return plus_one

# 列表推導(dǎo)式
def fast(lst):
 return [ x + 1 for x in lst ]

otime = timeit.timeit('origin(range(10))', globals=globals())
print("func origin exec time is {0}".format(otime))

ftime = timeit.timeit('fast(range(10))', globals=globals())
print("func origin exec time is {0}".format(ftime))

結(jié)果:

func origin exec time is 2.1059355960023822
func origin exec time is 1.6507169340038672

如果你使用map或者filter結(jié)合lambda生成列表,也是沒(méi)有列表推導(dǎo)式速度快的,有興趣的可以自己Coding一下。

列表的遍歷

在Python中常用循環(huán)對(duì)象來(lái)遍歷列表,在這里for循環(huán)自動(dòng)調(diào)用 next() 方法,將該方法的返回值賦予給循環(huán)對(duì)象。循環(huán)檢測(cè)到StopIteration的時(shí)候才結(jié)束。相對(duì)于序列,用循環(huán)對(duì)象的好處在于:不用在循環(huán)還沒(méi)有開(kāi)始的時(shí)候,就生成好要使用的元素。所使用的元素可以在循環(huán)過(guò)程中逐次生成。這樣,節(jié)省了空間,提高了效率,編程更靈活。

1. for循環(huán)遍歷

#!/usr/bin/env python3

map_list = ['China', 'America', 'Japan', 'Korea']

for countries in map_list:
 print(countries) # 自動(dòng)調(diào)用迭代器,自動(dòng)檢測(cè)StopIteration

# 在上面的程序中,無(wú)法知道當(dāng)前訪(fǎng)問(wèn)元素的索引,于是有如下代碼:
for index in range(len(map_list)):
 print("key is %s index is %s" % (map_list[index], index))

2. while循環(huán)遍歷

#!/usr/bin/env python3

map_list = ['China', 'America', 'Japan', 'Korea']

index = 0
while index < len(map_list):
 print(index, map_list[index])
 index+=1

3. 拉鏈(zip)方法遍歷

#!/usr/bin/env python3
map_list = ['China', 'America', 'Japan', 'Korea']
for index, value in zip(range(len(map_list)), map_list):
 print(index, value)

4. 利用Python內(nèi)置函數(shù) enumerate() 列舉

enumerate(iterable [, start ]) 返回枚舉對(duì)象, 參數(shù):

iterable: 一個(gè)序列、迭代器或其他支持迭代的對(duì)象
start: 下標(biāo)起始位置
#!/usr/bin/env python3
map_list = ['China', 'America', 'Japan', 'Korea']
for value in enumerate(map_list):
 print(value)

5. 使用 iter() 迭代器

iter(collection [, sentinel ]) 函數(shù)用來(lái)生成迭代器,返回迭代對(duì)象, 參數(shù):

collection: 支持迭代的集合對(duì)象

sentinel: 如果傳遞了第二個(gè)參數(shù),則參數(shù) object 必須是一個(gè)可調(diào)用的對(duì)象(如,函數(shù)),此時(shí), iter 創(chuàng)建了一個(gè)迭代器對(duì)象,每次調(diào)用這個(gè)迭代器對(duì)象的 __next__() 方法時(shí),都會(huì)調(diào)用object。

#!/usr/bin/env python3
map_list = ['China', 'America', 'Japan', 'Korea']
for value in iter(map_list):
 print(value)

由于列表在Python內(nèi)部的組成方式不同于C語(yǔ)言等,其索引的效率相對(duì)較為低下。因此在使用python的過(guò)程中,如果需要同時(shí)用到序號(hào)和元素,最好使用enumerate();當(dāng)我們不需要使用序號(hào)時(shí),在列表上直接進(jìn)行迭代效率最高。

元組

元組其實(shí)跟列表差不多,也是存一組數(shù),只不是它一旦創(chuàng)建,便不能再修改,所以又叫只讀列表。

語(yǔ)法: names = ('tom', 'jack', 'andy')

它只有2個(gè)方法,一個(gè)是count,一個(gè)是index:

class tuple(object):
 """
 tuple() -> empty tuple
 tuple(iterable) -> tuple initialized from iterable's items

 If the argument is a tuple, the return value is the same object.
 """
 def count(self, value): # real signature unknown; restored from __doc__
 """ T.count(value) -> integer -- return number of occurrences of value """
 return 0

 def index(self, value, start=None, stop=None): # real signature unknown; restored from __doc__
 """
 T.index(value, [start, [stop]]) -> integer -- return first index of value.
 Raises ValueError if the value is not present.
 """
 return 0

列表幾種高階常用場(chǎng)景

1. 解壓列表賦值給多個(gè)變量

現(xiàn)在有一個(gè)包含 N個(gè)元素 的元組或者列表,怎樣將它里面的值解壓后同時(shí)賦值給 N 個(gè)變量?

任何的序列(或者是可迭代對(duì)象)可以通過(guò)一個(gè)簡(jiǎn)單的賦值語(yǔ)句解壓并賦值給多個(gè)變量。 唯一的前提就是變量的數(shù)量必須跟序列元素的 數(shù)量一致 的。

代碼示例:

>>> jobs = ('hr', 'dev', 'ops')
>>> x, y, z = jobs
>>> print(x, y, z)
hr dev ops

>>> data = ['nock', 8, 24, (2001, 12, 28)]
>>> name, shares, size, date = data
>>> print(name, shares, size, date)
nock 8 24 (2001, 12, 28)
>>> date
(2001, 12, 28)
>>> name, shares, size, (year, mon, day) = data
>>> name
'nock'
>>> print(year, mon, day)
2001 12 28

如果變量個(gè)數(shù)和列表元素的個(gè)數(shù)不匹配,會(huì)產(chǎn)生異常的哦。

代碼示例:

>>> jobs = ('hr', 'dev', 'ops')
>>> x, y = jobs
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
>>> x, y, z, x = jobs
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 4, got 3)

實(shí)際上,這種解壓賦值可以用在任何可迭代對(duì)象上面,而不僅僅是列表或者元組。 包括字符串,文件對(duì)象,迭代器和生成器。

代碼示例:

>>> name = 'Jim'
>>> a, b, c = name
>>> a
'J'
>>> b
'i'

有時(shí)候,你可能只想解壓一部分,丟棄其他的值。對(duì)于這種情況 Python 并沒(méi)有提供特殊的語(yǔ)法。 但是你可以使用任意變量名去占位,到時(shí)候丟掉這些變量就行了。

>>> jobs = [18, 30000, 'duck', 100, (2000, 2, 18)]
>>> age, wage, _, num, _ = jobs
>>> age
18
>>> wage
30000
>>> _
(2000, 2, 18)

你必須保證你選用的那些占位變量名在其他地方?jīng)]被使用到。

2. 刪除列表中相同元素并保持順序

怎樣讓一個(gè)列表保持元素順序的同時(shí)消除重復(fù)的值,如果列表上的值都是 hashable 類(lèi)型,那么可以很簡(jiǎn)單的利用集合或者生成器來(lái)解決這個(gè)問(wèn)題,比如:

def dedupe(items):
 seen = set()
 for item in items:
 if item not in seen:
  yield item
  seen.add(item)

下面是使用上述函數(shù)的例子:

>>> def dedupe(items):
... seen = set()
... for item in items:
...  if item not in seen:
...  yield item
...  seen.add(item)
... 
>>> nums = [1, 5, 2, 1, 9, 1, 5, 10]
>>> list(dedupe(nums))
[1, 5, 2, 9, 10]

這個(gè)方法僅僅在序列中元素為 hashable 的時(shí)候才管用。 如果你想消除元素不可哈希(比如 dict 類(lèi)型)的序列中重復(fù)元素的話(huà),你需要將上述代碼稍微改變一下,就像這樣:

def dedupe(items, key=None):
 seen = set()
 for item in items:
 val = item if key is None else key(item)
 if val not in seen:
  yield item
  seen.add(val)

這里的key參數(shù)指定了一個(gè)函數(shù),將序列元素轉(zhuǎn)換成 hashable 類(lèi)型。下面是它的用法示例:

>>> a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
>>> list(dedupe(a, key=lambda d: (d['x'],d['y'])))
[{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]

>>> list(dedupe(a, key=lambda d: d['x']))
[{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]

如果你想基于單個(gè)字段、屬性或者某個(gè)更大的數(shù)據(jù)結(jié)構(gòu)來(lái)消除重復(fù)元素,第二種方案同樣可以勝任。

如果你僅僅就是想消除重復(fù)元素,通常可以簡(jiǎn)單的構(gòu)造一個(gè)集合。比如:

>>> a = [1, 5, 2, 1, 9, 1, 5, 10]
>>> list(set(a))
[1, 2, 10, 5, 9]

然而,這種方法不能維護(hù)元素的順序,生成的結(jié)果中的元素位置被打亂,而上面的方法可以避免這種情況。

我們使用了生成器函數(shù)讓我們的函數(shù)更加通用,不僅僅是局限于列表處理。 比如,如果如果你想讀取一個(gè)文件,消除重復(fù)行,你可以很容易像這樣做:

with open(somefile,'r') as f:
 for line in dedupe(f):
 ...

上述key函數(shù)參數(shù)模仿了 sorted() , min() 和 max() 等內(nèi)置函數(shù)的相似功能。

3. 統(tǒng)計(jì)列表中出現(xiàn)次數(shù)最多的元素

怎樣找出一個(gè)列表中出現(xiàn)次數(shù)最多的元素呢, collections.Counter 類(lèi)就是專(zhuān)門(mén)為這類(lèi)問(wèn)題而設(shè)計(jì)的, 它甚至有一個(gè)有用的 most_common() 方法直接給了你答案。

為了演示,先假設(shè)你有一個(gè)單詞列表并且想找出哪個(gè)單詞出現(xiàn)頻率最高。你可以這樣做:

>>> from collections import Counter
>>> words = [
... 'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',
... 'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the',
... 'eyes', "don't", 'look', 'around', 'the', 'eyes', 'look', 'into',
... 'my', 'eyes', "you're", 'under'
... ]
>>> 
>>> word_counts = Counter(words)
>>> top_three = word_counts.most_common(3)
>>> print(top_three)
[('eyes', 8), ('the', 5), ('look', 4)]

作為輸入, Counter 對(duì)象可以接受任意的由可哈希( hashable )元素構(gòu)成的序列對(duì)象。 在底層實(shí)現(xiàn)上,一個(gè) Counter 對(duì)象就是一個(gè)字典,將元素映射到它出現(xiàn)的次數(shù)上, 比如:

>>> word_counts['not']
1
>>> word_counts['eyes']
8

如果你想手動(dòng)增加計(jì)數(shù),可以簡(jiǎn)單的用加法:

>>> morewords = ['why','are','you','not','looking','in','my','eyes']
>>> for word in morewords:
... word_counts[word] += 1
...
>>> word_counts['eyes']
9

或者你可以使用 update() 方法:

word_counts.update(morewords)

Counter 實(shí)例一個(gè)鮮為人知的特性是它們可以很容易的跟數(shù)學(xué)運(yùn)算操作相結(jié)合,比如:

>>> a = Counter(words)
>>> b = Counter(morewords)
>>> a
Counter({'eyes': 8, 'the': 5, 'look': 4, 'into': 3, 'my': 3, 'around': 2,
"you're": 1, "don't": 1, 'under': 1, 'not': 1})
>>> b
Counter({'eyes': 1, 'looking': 1, 'are': 1, 'in': 1, 'not': 1, 'you': 1,
'my': 1, 'why': 1})
>>> # Combine counts
>>> c = a + b
>>> c
Counter({'eyes': 9, 'the': 5, 'look': 4, 'my': 4, 'into': 3, 'not': 2,
'around': 2, "you're": 1, "don't": 1, 'in': 1, 'why': 1,
'looking': 1, 'are': 1, 'under': 1, 'you': 1})
>>> # Subtract counts
>>> d = a - b
>>> d
Counter({'eyes': 7, 'the': 5, 'look': 4, 'into': 3, 'my': 2, 'around': 2,
"you're": 1, "don't": 1, 'under': 1})

毫無(wú)疑問(wèn), Counter 對(duì)象在幾乎所有需要制表或者計(jì)數(shù)數(shù)據(jù)的場(chǎng)合是非常有用的工具。 在解決這類(lèi)問(wèn)題的時(shí)候你應(yīng)該優(yōu)先選擇它,而不是手動(dòng)的利用字典去實(shí)現(xiàn)。

4. 過(guò)濾列表元素

你有一個(gè)數(shù)據(jù)列表,想利用一些規(guī)則從中提取出需要的值或者是縮短列表,最簡(jiǎn)單的過(guò)濾序列元素的方法就是使用列表推導(dǎo),比如:

>>> nums = [1, 2, -1, 4, 100, -2]
>>> [n for n in nums if n > 0]
[1, 2, 4, 100]
>>> [n for n in nums if n < 0]
[-1, -2]

使用列表推導(dǎo)的一個(gè)潛在缺陷就是如果輸入非常大的時(shí)候會(huì)產(chǎn)生一個(gè)非常大的結(jié)果集,占用大量?jī)?nèi)存。 如果你對(duì)內(nèi)存比較敏感,那么你可以使用生成器表達(dá)式迭代產(chǎn)生過(guò)濾的元素,比如:

>>> nums = [1, 2, -1, 4, 100, -2]
>>> num = (n for n in nums if n < 0)
>>> num
<generator object <genexpr> at 0x102210a50>
>>> for n in num:
... print(n)
... 
-1
-2

有時(shí)候,過(guò)濾規(guī)則比較復(fù)雜,不能簡(jiǎn)單的在列表推導(dǎo)或者生成器表達(dá)式中表達(dá)出來(lái)。 比如,假設(shè)過(guò)濾的時(shí)候需要處理一些異?;蛘咂渌麖?fù)雜情況。這時(shí)候你可以將過(guò)濾代碼放到一個(gè)函數(shù)中, 然后使用內(nèi)建的 filter() 函數(shù),示例如下:

values = ['1', '2', '-3', '-', '4', 'N/A', '5']
def is_int(val):
 try:
 x = int(val)
 return True
 except ValueError:
 return False
ivals = list(filter(is_int, values))
print(ivals)
# Outputs ['1', '2', '-3', '4', '5']

filter() 函數(shù)創(chuàng)建了一個(gè)迭代器,因此如果你想得到一個(gè)列表的話(huà),就得像示例那樣使用 list() 去轉(zhuǎn)換。

列表推導(dǎo)和生成器表達(dá)式通常情況下是過(guò)濾數(shù)據(jù)最簡(jiǎn)單的方式。 其實(shí)它們還能在過(guò)濾的時(shí)候轉(zhuǎn)換數(shù)據(jù),比如:

>>> mylist = [1, 4, -5, 10, -7, 2, 3, -1]
>>> import math
>>> [math.sqrt(n) for n in mylist if n > 0]
[1.0, 2.0, 3.1622776601683795, 1.4142135623730951, 1.7320508075688772]

過(guò)濾操作的一個(gè)變種就是將不符合條件的值用新的值代替,而不是丟棄它們。 比如,在一列數(shù)據(jù)中你可能不僅想找到正數(shù),而且還想將不是正數(shù)的數(shù)替換成指定的數(shù)。 通過(guò)將過(guò)濾條件放到條件表達(dá)式中去,可以很容易的解決這個(gè)問(wèn)題,就像這樣:

>>> mylist = [1, 4, -5, 10, -7, 2, 3, -1]
>>> clip_neg = [n if n > 0 else 0 for n in mylist]
>>> clip_neg
[1, 4, 0, 10, 0, 2, 3, 0]
>>> clip_pos = [n if n < 0 else 0 for n in mylist]
>>> clip_pos
[0, 0, -5, 0, -7, 0, 0, -1]

另外一個(gè)值得關(guān)注的過(guò)濾工具就是 itertools.compress() , 它以一個(gè) iterable 對(duì)象和一個(gè)相對(duì)應(yīng)的 Boolean 選擇器序列作為輸入?yún)?shù)。 然后輸出 iterable 對(duì)象中對(duì)應(yīng)選擇器為 True 的元素。 當(dāng)你需要用另外一個(gè)相關(guān)聯(lián)的序列來(lái)過(guò)濾某個(gè)序列的時(shí)候,這個(gè)函數(shù)是非常有用的。 比如,假如現(xiàn)在你有下面兩列數(shù)據(jù):

addresses = [
 '5412 N CLARK',
 '5148 N CLARK',
 '5800 E 58TH',
 '2122 N CLARK',
 '5645 N RAVENSWOOD',
 '1060 W ADDISON',
 '4801 N BROADWAY',
 '1039 W GRANVILLE',
]
counts = [ 0, 3, 10, 4, 1, 7, 6, 1]

現(xiàn)在你想將那些對(duì)應(yīng) count 值大于5的地址全部輸出,那么你可以這樣做:

>>> from itertools import compress
>>> more5 = [n > 5 for n in counts]
>>> more5
[False, False, True, False, False, True, True, False]
>>> list(compress(addresses, more5))
['5800 E 58TH', '1060 W ADDISON', '4801 N BROADWAY']

這里的關(guān)鍵點(diǎn)在于先創(chuàng)建一個(gè) Boolean 序列,指示哪些元素符合條件。 然后 compress() 函數(shù)根據(jù)這個(gè)序列去選擇輸出對(duì)應(yīng)位置為 True 的元素。

和 filter() 函數(shù)類(lèi)似, compress() 也是返回的一個(gè)迭代器。因此,如果你需要得到一個(gè)列表,那么你需要使用 list() 來(lái)將結(jié)果轉(zhuǎn)換為列表類(lèi)型。

5. 列表上索引值迭代

你想在迭代一個(gè)列表的同時(shí)跟蹤正在被處理的元素索引,內(nèi)置的 enumerate() 函數(shù)可以很好的解決這個(gè)問(wèn)題:

>>> my_list = ['a', 'b', 'c']
>>> for idx, val in enumerate(my_list):
... print(idx, val)
...
0 a
1 b
2 c

為了按傳統(tǒng)行號(hào)輸出(行號(hào)從1開(kāi)始),你可以傳遞一個(gè)開(kāi)始步長(zhǎng)值:

>>> my_list = ['a', 'b', 'c']
>>> for idx, val in enumerate(my_list, 1):
... print(idx, val)
...
1 a
2 b
3 c

這種情況在你遍歷文件時(shí)想在錯(cuò)誤消息中使用行號(hào)定位時(shí)候非常有用:

def parse_data(filename):
 with open(filename, 'rt') as f:
 for lineno, line in enumerate(f, 1):
  fields = line.split()
  try:
  count = int(fields[1])
  ...
  except ValueError as e:
  print('Line {}: Parse error: {}'.format(lineno, e))

enumerate() 對(duì)于跟蹤某些值在列表中出現(xiàn)的位置是很有用的。 所以,如果你想將一個(gè)文件中出現(xiàn)的單詞映射到它出現(xiàn)的行號(hào)上去,可以很容易的利用 enumerate() 來(lái)完成:

word_summary = defaultdict(list)

with open('myfile.txt', 'r') as f:
 lines = f.readlines()

for idx, line in enumerate(lines):
 # Create a list of words in current line
 words = [w.strip().lower() for w in line.split()]
 for word in words:
 word_summary[word].append(idx)

如果你處理完文件后打印 word_summary ,會(huì)發(fā)現(xiàn)它是一個(gè)字典(準(zhǔn)確來(lái)講是一個(gè) defaultdict ), 對(duì)于每個(gè)單詞有一個(gè) key ,每個(gè) key 對(duì)應(yīng)的值是一個(gè)由這個(gè)單詞出現(xiàn)的行號(hào)組成的列表。 如果某個(gè)單詞在一行中出現(xiàn)過(guò)兩次,那么這個(gè)行號(hào)也會(huì)出現(xiàn)兩次, 同時(shí)也可以作為文本的一個(gè)簡(jiǎn)單統(tǒng)計(jì)。

當(dāng)你想額外定義一個(gè)計(jì)數(shù)變量的時(shí)候,使用 enumerate() 函數(shù)會(huì)更加簡(jiǎn)單。你可能會(huì)像下面這樣寫(xiě)代碼:

lineno = 1
for line in f:
 # Process line
 ...
 lineno += 1

但是如果使用 enumerate() 函數(shù)來(lái)代替就顯得更加優(yōu)雅了:

for lineno, line in enumerate(f):
 # Process line
 ...

enumerate() 函數(shù)返回的是一個(gè) enumerate 對(duì)象實(shí)例, 它是一個(gè)迭代器,返回連續(xù)的包含一個(gè)計(jì)數(shù)和一個(gè)值的元組, 元組中的值通過(guò)在傳入序列上調(diào)用 next() 返回。

還有一點(diǎn)可能并不很重要,但是也值得注意, 有時(shí)候當(dāng)你在一個(gè)已經(jīng)解壓后的元組序列上使用 enumerate() 函數(shù)時(shí)很容易調(diào)入陷阱。 你得像下面正確的方式這樣寫(xiě):

data = [ (1, 2), (3, 4), (5, 6), (7, 8) ]
# Correct!
for n, (x, y) in enumerate(data):
 ...
# Error!
for n, x, y in enumerate(data):
 ...

6. 同時(shí)迭代多個(gè)列表

你想同時(shí)迭代多個(gè)列表,每次分別從一個(gè)序列中取一個(gè)元素, 為了同時(shí)迭代多個(gè)序列,使用 zip() 函數(shù),比如:

>>> xpts = [1, 5, 4, 2, 10, 7]
>>> ypts = [101, 78, 37, 15, 62, 99]
>>> for x, y in zip(xpts, ypts):
... print(x,y)
...
1 101
5 78
4 37
2 15
10 62
7 99

zip(a, b) 會(huì)生成一個(gè)可返回元組 (x, y) 的迭代器,其中x來(lái)自a,y來(lái)自b。 一旦其中某個(gè)序列到底結(jié)尾,迭代宣告結(jié)束。 因此迭代長(zhǎng)度跟參數(shù)中最短序列長(zhǎng)度一致。

>>> a = [1, 2, 3]
>>> b = ['w', 'x', 'y', 'z']
>>> for i in zip(a,b):
... print(i)
...
(1, 'w')
(2, 'x')
(3, 'y')

如果這個(gè)不是你想要的效果,那么還可以使用 itertools.zip_longest() 函數(shù)來(lái)代替,比如:

>>> from itertools import zip_longest
>>> for i in zip_longest(a,b):
... print(i)
...
(1, 'w')
(2, 'x')
(3, 'y')
(None, 'z')

>>> for i in zip_longest(a, b, fillvalue=0):
... print(i)
...
(1, 'w')
(2, 'x')
(3, 'y')
(0, 'z')

當(dāng)你想成對(duì)處理數(shù)據(jù)的時(shí)候 zip() 函數(shù)是很有用的。 比如,假設(shè)你headers列表和一個(gè)values列表,就像下面這樣:

headers = ['name', 'shares', 'price']
values = ['ACME', 100, 490.1]

使用zip()可以讓你將它們打包并生成一個(gè)字典:

s = dict(zip(headers,values))

或者你也可以像下面這樣產(chǎn)生輸出:

for name, val in zip(headers, values):
 print(name, '=', val)

雖然不常見(jiàn),但是 zip() 可以接受多于兩個(gè)的序列的參數(shù)。 這時(shí)候所生成的結(jié)果元組中元素個(gè)數(shù)跟輸入序列個(gè)數(shù)一樣, 比如:

>>> a = [1, 2, 3]
>>> b = [10, 11, 12]
>>> c = ['x','y','z']
>>> for i in zip(a, b, c):
... print(i)
...
(1, 10, 'x')
(2, 11, 'y')
(3, 12, 'z')

最后強(qiáng)調(diào)一點(diǎn)就是, zip() 會(huì)創(chuàng)建一個(gè)迭代器來(lái)作為結(jié)果返回。 如果你需要將結(jié)對(duì)的值存儲(chǔ)在列表中,要使用 list() 函數(shù),比如:

>>> zip(a, b)
<zip object at 0x1007001b8>
>>> list(zip(a, b))
[(1, 10), (2, 11), (3, 12)]

7. 展開(kāi)嵌透的列表

你想將一個(gè)多層嵌套的列表展開(kāi)成一個(gè)單層列表, 可以寫(xiě)一個(gè)包含 yield from 語(yǔ)句的遞歸生成器來(lái)輕松解決這個(gè)問(wèn)題。比如:

from collections import Iterable
def flatten(items, ignore_types=(str, bytes)):
 for x in items:
 if isinstance(x, Iterable) and not isinstance(x, ignore_types):
  yield from flatten(x)
 else:
  yield x

items = [1, 2, [3, 4, [5, 6], 7], 8]
# Produces 1 2 3 4 5 6 7 8
for x in flatten(items):
 print(x)

在上面代碼中, isinstance(x, Iterable) 檢查某個(gè)元素是否是可迭代的。 如果是的話(huà) yield from 就會(huì)返回所有子例程的值。最終返回結(jié)果就是一個(gè)沒(méi)有嵌套的簡(jiǎn)單列表了。

額外的參數(shù) ignore_types 和檢測(cè)語(yǔ)句 isinstance(x, ignore_types) 用來(lái)將字符串和字節(jié)排除在可迭代對(duì)象外,防止將它們?cè)僬归_(kāi)成單個(gè)的字符。 這樣的話(huà)字符串?dāng)?shù)組就能最終返回我們所期望的結(jié)果了。比如:

>>> items = ['Dave', 'Paula', ['Thomas', 'Lewis']]
>>> for x in flatten(items):
... print(x)
...
Dave
Paula
Thomas
Lewis

語(yǔ)句 yield from 在你想在生成器中調(diào)用其他生成器作為子例程的時(shí)候非常有用。 如果你不使用它的話(huà),那么就必須寫(xiě)額外的 for 循環(huán)了,比如:

def flatten(items, ignore_types=(str, bytes)):
 for x in items:
 if isinstance(x, Iterable) and not isinstance(x, ignore_types):
  for i in flatten(x):
  yield i
 else:
  yield x

盡管只改了一點(diǎn)點(diǎn),但是 yield from 語(yǔ)句看上去感覺(jué)更好,并且也使得代碼更簡(jiǎn)潔清爽。

之前提到的對(duì)于字符串和字節(jié)的額外檢查是為了防止將它們?cè)僬归_(kāi)成單個(gè)字符。 如果還有其他你不想展開(kāi)的類(lèi)型,修改參數(shù) ignore_types 即可。

最后要注意的一點(diǎn)是 yield from 在涉及到基于協(xié)程和生成器的并發(fā)編程中扮演著更加重要的角色。

8. 映射名稱(chēng)到列表元素

你有一段通過(guò)下標(biāo)訪(fǎng)問(wèn)列表或者元組中元素的代碼,但是這樣有時(shí)候會(huì)使得你的代碼難以閱讀, 于是你想通過(guò)名稱(chēng)來(lái)訪(fǎng)問(wèn)元素。

·collections.namedtuple()·函數(shù)通過(guò)使用一個(gè)普通的元組對(duì)象來(lái)幫你解決這個(gè)問(wèn)題。 這個(gè)函數(shù)實(shí)際上是一個(gè)返回Python中標(biāo)準(zhǔn)元組類(lèi)型子類(lèi)的一個(gè)工廠(chǎng)方法。 你需要傳遞一個(gè)類(lèi)型名和你需要的字段給它,然后它就會(huì)返回一個(gè)類(lèi),你可以初始化這個(gè)類(lèi),為你定義的字段傳遞值等。 代碼示例:

>>> from collections import namedtuple
>>> Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
>>> sub = Subscriber('jonesy@example.com', '2012-10-19')
>>> sub
Subscriber(addr='jonesy@example.com', joined='2012-10-19')
>>> sub.addr
'jonesy@example.com'
>>> sub.joined
'2012-10-19'

盡管 namedtuple 的實(shí)例看起來(lái)像一個(gè)普通的類(lèi)實(shí)例,但是它跟元組類(lèi)型是可交換的,支持所有的普通元組操作,比如索引和解壓。 比如:

>>> len(sub)
2
>>> addr, joined = sub
>>> addr
'jonesy@example.com'
>>> joined
'2012-10-19'

命名元組的一個(gè)主要用途是將你的代碼從下標(biāo)操作中解脫出來(lái)。 因此,如果你從數(shù)據(jù)庫(kù)調(diào)用中返回了一個(gè)很大的元組列表,通過(guò)下標(biāo)去操作其中的元素, 當(dāng)你在表中添加了新的列的時(shí)候你的代碼可能就會(huì)出錯(cuò)了。但是如果你使用了命名元組,那么就不會(huì)有這樣的顧慮。

為了說(shuō)明清楚,下面是使用普通元組的代碼:

def compute_cost(records):
 total = 0.0
 for rec in records:
 total += rec[1] * rec[2]
 return total

下標(biāo)操作通常會(huì)讓代碼表意不清晰,并且非常依賴(lài)記錄的結(jié)構(gòu)。 下面是使用命名元組的版本:

from collections import namedtuple

Stock = namedtuple('Stock', ['name', 'shares', 'price'])
def compute_cost(records):
 total = 0.0
 for rec in records:
 s = Stock(*rec)
 total += s.shares * s.price
 return total

命名元組另一個(gè)用途就是作為字典的替代,因?yàn)樽值浯鎯?chǔ)需要更多的內(nèi)存空間。 如果你需要構(gòu)建一個(gè)非常大的包含字典的數(shù)據(jù)結(jié)構(gòu),那么使用命名元組會(huì)更加高效。 但是需要注意的是,不像字典那樣,一個(gè)命名元組是不可更改的。比如:

>>> s = Stock('ACME', 100, 123.45)
>>> s
Stock(name='ACME', shares=100, price=123.45)
>>> s.shares = 75
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

如果你真的需要改變屬性的值,那么可以使用命名元組實(shí)例的 _replace() 方法, 它會(huì)創(chuàng)建一個(gè)全新的命名元組并將對(duì)應(yīng)的字段用新的值取代。比如:

>>> s = s._replace(shares=75)
>>> s
Stock(name='ACME', shares=75, price=123.45)

_replace() 方法還有一個(gè)很有用的特性就是當(dāng)你的命名元組擁有可選或者缺失字段時(shí)候, 它是一個(gè)非常方便的填充數(shù)據(jù)的方法。 你可以先創(chuàng)建一個(gè)包含缺省值的原型元組,然后使用 _replace() 方法創(chuàng)建新的值被更新過(guò)的實(shí)例。比如:

from collections import namedtuple
Stock = namedtuple('Stock', ['name', 'shares', 'price', 'date', 'time'])
# Create a prototype instance
stock_prototype = Stock('', 0, 0.0, None, None)
# Function to convert a dictionary to a Stock
def dict_to_stock(s):
 return stock_prototype._replace(**s)

下面是它的使用方法:

>>> a = {'name': 'ACME', 'shares': 100, 'price': 123.45}
>>> dict_to_stock(a)
Stock(name='ACME', shares=100, price=123.45, date=None, time=None)
>>> b = {'name': 'ACME', 'shares': 100, 'price': 123.45, 'date': '12/17/2012'}
>>> dict_to_stock(b)
Stock(name='ACME', shares=100, price=123.45, date='12/17/2012', time=None)

最后要說(shuō)的是,如果你的目標(biāo)是定義一個(gè)需要更新很多實(shí)例屬性的高效數(shù)據(jù)結(jié)構(gòu),那么命名元組并不是你的最佳選擇。 這時(shí)候你應(yīng)該考慮定義一個(gè)包含 slots 方法的類(lèi).

總結(jié)

以上所述是小編給大家介紹的Python數(shù)據(jù)類(lèi)型之列表和元組的方法實(shí)例詳解,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)億速云網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI