博客地址:https://www.hz-bin.cn/Effective_Python_2
第11條 學(xué)會對序列做切片
- 最基本的寫法是用somelist[start:end]這一形式來切割,也就是從start開始一直取到end這個位置,但不包含end本身的元素。切割出來的列表是一份全新的列表
a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
a[:] # ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
a[:5] # ['a', 'b', 'c', 'd', 'e']
a[:-1] # ['a', 'b', 'c', 'd', 'e', 'f', 'g']
a[4:] # ['e', 'f', 'g', 'h']
a[-3:] # ['f', 'g', 'h']
a[2:5] # ['c', 'd', 'e']
a[2:-1] # ['c', 'd', 'e', 'f', 'g']
a[-3:-1]# ['f', 'g']
- 切片可以出現(xiàn)在賦值符號的左側(cè),表示用右側(cè)那些元素把原列表中位于這個范圍之內(nèi)的元素?fù)Q掉,不要求兩邊元素個數(shù)相同
a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
a[2:7] = [99, 22, 14]
# a 變成:['a', 'b', 99, 22, 14, 'h']
a[2:3] = [47, 11]
# a 變成:['a', 'b', 47, 11, 22, 14, 'h']
a = [1, 2, 3]
b = a
print(a, b)
# ([1, 2, 3], [1, 2, 3])
a[:] = [101, 102, 103]
print(a, b)
# ([101, 102, 103], [101, 102, 103])
第12條 不要在切片里同時指定起止下標(biāo)與步進(jìn)
- Python還有一種特殊的步進(jìn)切片形式,也就是
somelist[start:end:stride]。這種形式會在每n個元素里面選取一個,這樣很容易就能把奇數(shù)位置上的元素與偶數(shù)位置上的元素分別通過x[::2]與x[1::2]選取出來 - 同時指定切片的起止下標(biāo)與步進(jìn)值理解起來會很困難。
- 如果要指定步進(jìn)值,那就省略起止下標(biāo),而且最好采用正數(shù)作為步進(jìn)值,盡量別用負(fù)數(shù)。
- 不要把起始位置、終止位置與步進(jìn)值全都寫在同一個切片操作里。如果必須同時使用這三項指標(biāo),那就分兩次來做(其中一次隔位選取,另一次做切割),也可以改用itertools內(nèi)置模塊里的islice方法。
第13條 通過帶星號的unpacking操作來捕獲多個元素,不要用切片
car_ages = [0, 9, 4, 8, 7, 20, 19, 1, 6, 15]
car_ages_desceding = sorted(car_ages, reverse=True)
oldest, second_oldest, *others = car_ages_descending
oldest, *others, yongest = car_ages_descending
- 使用這種寫法時,至少要有一個普通的接收變量與它搭配,否則就會出現(xiàn)SyntaxError。
第14條 用sort方法的key參數(shù)來表示復(fù)雜的排序邏輯
class Tool:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __repr__(self):
return f'Tool({self.name!r}, self.weight)'
tools = [
Tool('level', 3.5),
Tool('hammer', 0.25),
Tool('screwdriver', 0.5),
Tool('chisel', 0.25),
]
tools.sort(key=lambda x: x.name)
# 先按weight排序,再按name排序。reverse=True表示逆序
tools.sort(key=lambda x: (x.weight, x.name), reverse=True)
# weight逆序,name正序
tools.sort(key=lambda x: (-x.weight, x.name))
第15條 不要過分依賴給字典添加條目時所用的順序
- 在Python 3.5與之前的版本中,dict所提供的許多方法(包括keys、values、items與popitem等)都不保證固定的順序。
- 從Python 3.6開始,字典會保留這些鍵值對在添加時所用的順序,而且Python3.7版的語言規(guī)范正式確立了這條規(guī)則。
第16條 用get處理鍵不在字典中的情況,不要使用in與KeyError
- 有四種辦法可以處理鍵不在字典中的情況:in表達(dá)式、KeyError異常、get方法與setdefault方法。
- 如果跟鍵相關(guān)聯(lián)的值是像計數(shù)器這樣的基本類型,那么get方法就是最好的方案;如果是那種構(gòu)造起來開銷比較大,或是容易出異常的類型,那么可以把這個方法與賦值表達(dá)式結(jié)合起來使用。
- 即使看上去最應(yīng)該使用setdefault方案,也不一定要真的使用setdefault方案,而是可以考慮用defaultdict取代普通的dict。
第17條 用defaultdict處理內(nèi)部狀態(tài)中缺失的元素,而不要用setdefault
- 如果你管理的字典可能需要添加任意的鍵,那么應(yīng)該考慮能否用內(nèi)置的collections模塊中的defaultdict實(shí)例來解決問題。
- 如果這種鍵名比較隨意的字典是別人傳給你的,你無法把它創(chuàng)建成defaultdict,那么應(yīng)該考慮通過get方法訪問其中的鍵值。然而,在個別情況下,也可以考慮改用setdefault方法,因為那樣寫更短。
from collections import defaultdict
class Visits:
def __init__(self):
self.data = defaultdict(set)
def add(self, country, city):
self.data[country].add(city)
第18條 學(xué)會利用missing構(gòu)造依賴鍵的默認(rèn)值
class Pictures(dict):
def __missing__(self, key):
value = open_picture(key)
self[key] = value
return value
pictures = Pictures()
handle = pictures[path]
handle.seek(0)
image_data = handle.read()
- 如果創(chuàng)建默認(rèn)值需要較大的開銷,或者可能拋出異常,那就不適合用dict類型的setdefault方法實(shí)現(xiàn)。
- 傳給defaultdict的函數(shù)必須是不需要參數(shù)的函數(shù),所以無法創(chuàng)建出需要依賴鍵名的默認(rèn)值。
- 如果要構(gòu)造的默認(rèn)值必須根據(jù)鍵名來確定,那么可以定義自己的dict子類并實(shí)現(xiàn)missing方法。