第3章 Python的数据结构、函数和文件
元祖
如果元組中的某個對象是可變的,比如列表,可以用append或者extend在原地進行修改:
In [11]: tup[1].append(3)In [12]: tup Out[12]: ('foo', [1, 2, 3], True)Python最近新增了更多高級的元組拆分功能,允許從元組的開頭“摘取”幾個元素。它使用了特殊的語法*rest,這也用在函數簽名中以抓取任意長度列表的位置參數:
In [29]: values = 1, 2, 3, 4, 5 In [30]: a, b, *rest = values In [31]: a, b Out[31]: (1, 2) In [32]: rest Out[32]: [3, 4, 5]rest的部分是想要舍棄的部分,rest的名字不重要。作為慣用寫法,許多Python程序員會將不需要的變量使用下劃線:
In [33]: a, b, *_ = values二分搜索和維護已排序的列表
bisect模塊支持二分查找,和向已排序的列表插入值。bisect.bisect可以找到插入值后仍保證排序的位置,bisect.insort是向這個位置插入值:
In [67]: import bisectIn [68]: c = [1, 2, 2, 2, 3, 4, 7] In [69]: bisect.bisect(c, 2) Out[69]: 4 In [70]: bisect.bisect(c, 5) Out[70]: 6 In [71]: bisect.insort(c, 6) In [72]: c Out[72]: [1, 2, 2, 2, 3, 4, 6, 7]注意:bisect模塊不會檢查列表是否已排好序,進行檢查的話會耗費大量計算。因此,對未排序的列表使用bisect不會產生錯誤,但結果不一定正確。
enumerate函數
迭代一個序列時,你可能想跟蹤當前項的序號。手動的方法可能是下面這樣:
i = 0 for value in collection:# do something with value i += 1因為這么做很常見,Python內建了一個enumerate函數,可以返回(i, value)元組序列:
for i, value in enumerate(collection):# do something with value當你索引數據時,使用enumerate的一個好方法是計算序列(唯一的)dict映射到位置的值:
In [83]: some_list = ['foo', 'bar', 'baz'] In [84]: mapping = {} In [85]: for i, v in enumerate(some_list): ....: mapping[v] = i In [86]: mapping Out[86]: {'bar': 1, 'baz': 2, 'foo': 0}zip函數
zip可以將多個列表、元組或其它序列成對組合成一個元組列表:
In [89]: seq1 = ['foo', 'bar', 'baz'] In [90]: seq2 = ['one', 'two', 'three'] In [91]: zipped = zip(seq1, seq2) In [92]: list(zipped) Out[92]: [('foo', 'one'), ('bar', 'two'), ('baz', 'three')]zip可以處理任意多的序列,元素的個數取決于最短的序列:
In [93]: seq3 = [False, True]In [94]: list(zip(seq1, seq2, seq3)) Out[94]: [('foo', 'one', False), ('bar', 'two', True)]zip的常見用法之一是同時迭代多個序列,可能結合enumerate使用:
In [95]: for i, (a, b) in enumerate(zip(seq1, seq2)):....: print('{0}: {1}, {2}'.format(i, a, b)) ....: 0: foo, one 1: bar, two 2: baz, three給出一個“被壓縮的”序列,zip可以被用來解壓序列。也可以當作把行的列表轉換為列的列表。這個方法看起來有點神奇:
In [96]: pitchers = [('Nolan', 'Ryan'), ('Roger', 'Clemens'), ....: ('Schilling', 'Curt')] In [97]: first_names, last_names = zip(*pitchers) In [98]: first_names Out[98]: ('Nolan', 'Roger', 'Schilling') In [99]: last_names Out[99]: ('Ryan', 'Clemens', 'Curt')reversed函數
reversed可以從后向前迭代一個序列:
In [100]: list(reversed(range(10))) Out[100]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]要記住reversed是一個生成器(后面詳細介紹),只有實體化(即列表或for循環)之后才能創建翻轉的序列。
字典
keys和values是字典的鍵和值的迭代器方法。雖然鍵值對沒有順序,這兩個方法可以用相同的順序輸出鍵和值:
In [117]: list(d1.keys()) Out[117]: ['a', 'b', 7] In [118]: list(d1.values()) Out[118]: ['some value', [1, 2, 3, 4], 'an integer']用update方法可以將一個字典與另一個融合:
In [119]: d1.update({'b' : 'foo', 'c' : 12}) In [120]: d1 Out[120]: {'a': 'some value', 'b': 'foo', 7: 'an integer', 'c': 12}update方法是原地改變字典,因此任何傳遞給update的鍵的舊的值都會被舍棄。
用序列創建字典
常常,你可能想將兩個序列配對組合成字典。下面是一種寫法:
mapping = {} for key, value in zip(key_list, value_list):mapping[key] = value因為字典本質上是2元元組的集合,dict可以接受2元元組的列表:
In [121]: mapping = dict(zip(range(5), reversed(range(5))))In [122]: mapping Out[122]: {0: 4, 1: 3, 2: 2, 3: 1, 4: 0}下面的邏輯很常見:
if key in some_dict:value = some_dict[key] else:value = default_value因此,dict的方法get和pop可以取默認值進行返回,上面的if-else語句可以簡寫成下面:
value = some_dict.get(key, default_value)get默認會返回None,如果不存在鍵,pop會拋出一個例外。關于設定值,常見的情況是在字典的值是屬于其它集合,如列表。例如,你可以通過首字母,將一個列表中的單詞分類:
In [123]: words = ['apple', 'bat', 'bar', 'atom', 'book'] In [124]: by_letter = {} In [125]: for word in words: .....: letter = word[0] .....: if letter not in by_letter: .....: by_letter[letter] = [word] .....: else: .....: by_letter[letter].append(word) .....: In [126]: by_letter Out[126]: {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}setdefault方法就正是干這個的。前面的for循環可以改寫為:
for word in words:letter = word[0]by_letter.setdefault(letter, []).append(word)collections模塊有一個很有用的類,defaultdict,它可以進一步簡化上面。傳遞類型或函數以生成每個位置的默認值:
from collections import defaultdict by_letter = defaultdict(list) for word in words: by_letter[word[0]].append(word)嵌套列表推導式
假設我們有一個包含列表的列表,包含了一些英文名和西班牙名:
In [161]: all_data = [['John', 'Emily', 'Michael', 'Mary', 'Steven'], .....: ['Maria', 'Juan', 'Javier', 'Natalia', 'Pilar']]你可能是從一些文件得到的這些名字,然后想按照語言進行分類?,F在假設我們想用一個列表包含所有的名字,這些名字中包含兩個或更多的e??梢杂胒or循環來做:
names_of_interest = [] for names in all_data:enough_es = [name for name in names if name.count('e') >= 2] names_of_interest.extend(enough_es)可以用嵌套列表推導式的方法,將這些寫在一起,如下所示:
In [162]: result = [name for names in all_data for name in names .....: if name.count('e') >= 2] In [163]: result Out[163]: ['Steven']嵌套列表推導式看起來有些復雜。列表推導式的for部分是根據嵌套的順序,過濾條件還是放在最后。下面是另一個例子,我們將一個整數元組的列表扁平化成了一個整數列表:
In [164]: some_tuples = [(1, 2, 3), (4, 5, 6), (7, 8, 9)] In [165]: flattened = [x for tup in some_tuples for x in tup] In [166]: flattened Out[166]: [1, 2, 3, 4, 5, 6, 7, 8, 9]記住,for表達式的順序是與嵌套for循環的順序一樣(而不是列表推導式的順序):
flattened = []for tup in some_tuples:for x in tup: flattened.append(x)你可以有任意多級別的嵌套,但是如果你有兩三個以上的嵌套,你就應該考慮下代碼可讀性的問題了。分辨列表推導式的列表推導式中的語法也是很重要的:
In [167]: [[x for x in tup] for tup in some_tuples] Out[167]: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]這段代碼產生了一個列表的列表,而不是扁平化的只包含元素的列表。
柯里化:部分參數應用
柯里化(currying)是一個有趣的計算機科學術語,它指的是通過“部分參數應用”(partial argument application)從現有函數派生出新函數的技術。例如,假設我們有一個執行兩數相加的簡單函數:
def add_numbers(x, y): return x + y通過這個函數,我們可以派生出一個新的只有一個參數的函數——add_five,它用于對其參數加5:
add_five = lambda y: add_numbers(5, y)add_numbers的第二個參數稱為“柯里化的”(curried)。這里沒什么特別花哨的東西,因為我們其實就只是定義了一個可以調用現有函數的新函數而已。內置的functools模塊可以用partial函數將此過程簡化:
from functools import partial add_five = partial(add_numbers, 5)轉載于:https://www.cnblogs.com/wjw2018/p/10785341.html
總結
以上是生活随笔為你收集整理的第3章 Python的数据结构、函数和文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python中sort命令介绍以及lis
- 下一篇: [SQL]批量修改存储过程视图