Python核心技術(shù)與實(shí)戰(zhàn):學(xué)習(xí)筆記(一)

03|列表和元組,到底用哪一個(gè)唉堪?

列表是動(dòng)態(tài)的模聋,長度大小不固定,可以隨意地增加唠亚、刪減或者改變元素(mutable)链方。 而元組是靜態(tài)的,長度大小固定灶搜,無法增加刪減或者改變(immutable)祟蚀。

count(item) 表示統(tǒng)計(jì)列表 / 元組中 item 出現(xiàn)的次數(shù)。

index(item) 表示返回列表 / 元組中 item 第一次出現(xiàn)的索引割卖。

list.reverse() 和 list.sort() 分別表示原地倒轉(zhuǎn)列表和排序(注意前酿,元組沒有內(nèi)置的這兩個(gè) 函數(shù))。

reversed() 和 sorted() 同樣表示對列表 / 元組進(jìn)行倒轉(zhuǎn)和排序鹏溯,但是會(huì)返回一個(gè)倒轉(zhuǎn)后 或者排好序的新的列表 / 元組罢维。

l = [1, 2, 3]
l.__sizeof__()
#64
tup = (1, 2, 3)
tup.__sizeof__()
#48

l = []
l.__sizeof__() // 空列表的存儲(chǔ)空間為 40 字節(jié)
40
l.append(1)
l.__sizeof__()
72 // 加入了元素 1 之后,列表為其分配了可以存儲(chǔ) 4 個(gè)元素的空間 (72 - 40)/8 = 4
l.append(2)
l.__sizeof__()
72 // 由于之前分配了空間丙挽,所以加入元素 2肺孵,列表空間不變
l.append(3)
l.__sizeof__()
72 // 同上
l.append(4)
l.__sizeof__()
72 // 同上
l.append(5)
l.__sizeof__()
104 // 加入元素 5 之后,列表的空間不足颜阐,所以又額外分配了可以存儲(chǔ) 4 個(gè)元素的空間
python3 -m timeit 'x=(1,2,3,4,5,6)'
20000000 loops, best of 5: 9.97 nsec per loop
python3 -m timeit 'x=[1,2,3,4,5,6]'
5000000 loops, best of 5: 50.1 nsec per loop

04 | 字典平窘、集合,你真的了解嗎凳怨?

集合并不支持索引操作瑰艘,因?yàn)榧媳举|(zhì)上是一個(gè)哈希表,和列表不一 樣猿棉。

#字典和集合的創(chuàng)建方式
d1 = {'name': 'jason', 'age': 20, 'gender': 'male'}
d2 = dict({'name': 'jason', 'age': 20, 'gender': 'male'})
d3 = dict([('name', 'jason'), ('age', 20), ('gender', 'male')])
d4 = dict(name='jason', age=20, gender='male')
print(d1 == d2 == d3 ==d4)
# True
s1 = {1, 2, 3}
s2 = set([1, 2, 3])
print(s2)
# {1, 2, 3}
print(s1 == s2)
# True

字典訪問可以直接索引鍵磅叛,如果不存在,就會(huì)拋出異常萨赁;也可以使用 get(key, default) 函數(shù)來進(jìn)行索引弊琴。如果鍵不存在,調(diào)用 get() 函數(shù)可以返回 一個(gè)默認(rèn)值杖爽。

集合并不支持索引操作敲董,因?yàn)榧媳举|(zhì)上是一個(gè)哈希表紫皇,和列表不一 樣。

想要判斷一個(gè)元素在不在字典或集合內(nèi)腋寨,我們可以用 value in dict/set 來判斷聪铺。

插入操作

每次向字典或集合插入一個(gè)元素時(shí),Python 會(huì)首先計(jì)算鍵的哈希值(hash(key))萄窜,再和 mask = PyDicMinSize - 1 做與操作铃剔,計(jì)算這個(gè)元素應(yīng)該插入哈希表的位置 index = hash(key) & mask。如果哈希表中此位置是空的查刻,那么這個(gè)元素就會(huì)被插入其中键兜。 而如果此位置已被占用,Python 便會(huì)比較兩個(gè)元素的哈希值和鍵是否相等穗泵。若兩者都相等普气,則表明這個(gè)元素已經(jīng)存在,如果值不同佃延,則更新值现诀。 若兩者中有一個(gè)不相等,這種情況我們通常稱為哈希沖突(hash collision)履肃,意思是兩 個(gè)元素的鍵不相等仔沿,但是哈希值相等。這種情況下尺棋,Python 便會(huì)繼續(xù)尋找表中空余的位置于未,直到找到位置為止。

值得一提的是陡鹃,通常來說烘浦,遇到這種情況,最簡單的方式是線性尋找萍鲸,即從這個(gè)位置開始闷叉, 挨個(gè)往后尋找空位。當(dāng)然脊阴,Python 內(nèi)部對此進(jìn)行了優(yōu)化(這一點(diǎn)無需深入了解握侧,你有興趣 可以查看源碼,我就不再贅述)嘿期,讓這個(gè)步驟更加高效品擎。 查找操作 和前面的插入操作類似,Python 會(huì)根據(jù)哈希值备徐,找到其應(yīng)該處于的位置萄传;然后,比較哈希 表這個(gè)位置中元素的哈希值和鍵蜜猾,與需要查找的元素是否相等秀菱。如果相等振诬,則直接返回;如 果不等衍菱,則繼續(xù)查找赶么,直到找到空位或者拋出異常為止。

刪除操作

對于刪除操作脊串,Python 會(huì)暫時(shí)對這個(gè)位置的元素辫呻,賦于一個(gè)特殊的值,等到重新調(diào)整哈希 表的大小時(shí)琼锋,再將其刪除印屁。 不難理解,哈希沖突的發(fā)生斩例,往往會(huì)降低字典和集合操作的速度。因此从橘,為了保證其高效 性念赶,字典和集合內(nèi)的哈希表,通常會(huì)保證其至少留有 1/3 的剩余空間恰力。隨著元素的不停插 入叉谜,當(dāng)剩余空間小于 1/3 時(shí)踩萎,Python 會(huì)重新獲取更大的內(nèi)存空間,擴(kuò)充哈希表香府。不過,這 種情況下企孩,表內(nèi)所有的元素位置都會(huì)被重新排放。 雖然哈希沖突和哈希表大小的調(diào)整勿璃,都會(huì)導(dǎo)致速度減緩擒抛,但是這種情況發(fā)生的次數(shù)極少歧沪。所 以,平均情況下莲组,這仍能保證插入诊胞、查找和刪除的時(shí)間復(fù)雜度為 O(1)。

05 | 深入淺出字符串

常見的的轉(zhuǎn)義字符

Python 的字符串是不可變的(immutable)锹杈,Python 中字符串的改變厢钧,通常只能通過創(chuàng)建新的字符串來完成鳞尔。

s='HKSIHh'
s = 'H' + s[1:]
s = s.replace('h', 'H'

你可能了解到,在其他語言中早直,如 Java寥假,有可變的字符串類型,比如 StringBuilder霞扬,每次 添加糕韧、改變或刪除字符(串),無需創(chuàng)建新的字符串喻圃,時(shí)間復(fù)雜度僅為 O(1)萤彩。這樣就大大 提高了程序的運(yùn)行效率。 但可惜的是斧拍,Python 中并沒有相關(guān)的數(shù)據(jù)類型雀扶,我們還是得老老實(shí)實(shí)創(chuàng)建新的字符串。因 此肆汹,每次想要改變字符串愚墓,往往需要 O(n) 的時(shí)間復(fù)雜度,其中昂勉,n 為新字符串的長度浪册。

s = ''
for n in range(0, 100000):
 s += str(n)

自從 Python2.5 開始,每次處理字符串的拼接操作時(shí)(str1 += str2)岗照,Python 首先會(huì)檢 測 str1 還有沒有其他的引用村象。如果沒有的話,就會(huì)嘗試原地?cái)U(kuò)充字符串 buffer 的大小攒至,而 不是重新分配一塊內(nèi)存來創(chuàng)建新的字符串并拷貝厚者。

這樣的話,上述例子中的時(shí)間復(fù)雜度就僅 為 O(n) 了迫吐。

因此籍救,以后你在寫程序遇到字符串拼接時(shí),如果使用’+='更方便渠抹,就放心地去用吧蝙昙,不用 過分擔(dān)心效率問題了。 另外梧却,對于字符串拼接問題奇颠,除了使用加法操作符,我們還可以使用字符串內(nèi)置的 join 函 數(shù)放航。string.join(iterable)烈拒,表示把每個(gè)元素都按照指定的格式連接起來。

l = []
for n in range(0, 100000):
 l.append(str(n))
l = ' '.join(l) 

#由于列表的 append 操作是 O(1) 復(fù)雜度,字符串同理荆几。因此吨铸,這個(gè)含有 for 循環(huán)例子的時(shí)
間復(fù)雜度為 n*O(1)=O(n)。

string.strip(str)舟奠,表示去掉首尾的 str 字符串房维; string.lstrip(str),表示只去掉開頭的 str 字符串耿戚; string.rstrip(str)阿趁,表示只去掉尾部的 str 字符串歌焦。

06 | Python “黑箱”:輸入與輸出

讓我們來做一個(gè)簡單的 NLP(自然語言處理)任務(wù)独撇。如果你對此不太了解也沒有影 響躁锁,我會(huì)帶你一步步完成這個(gè)任務(wù)。

首先搜立,我們要清楚 NLP 任務(wù)的基本步驟槐秧,也就是下面的四步: 1. 讀取文件刁标; 2. 去除所有標(biāo)點(diǎn)符號(hào)和換行符,并把所有大寫變成小寫顿锰; 3. 合并相同的詞,統(tǒng)計(jì)每個(gè)詞出現(xiàn)的頻率刘陶,并按照詞頻從大到小排序牢撼; 4. 將結(jié)果按行輸出到文件 out.txt。 你可以自己先思考一下浪默,用 Python 如何解決這個(gè)問題。這里碰逸,我也給出了我的代碼阔加,并附 有詳細(xì)的注釋胜榔。我們一起來看下這段代碼。

import re
# 你不用太關(guān)心這個(gè)函數(shù)
def parse(text):
 # 使用正則表達(dá)式去除標(biāo)點(diǎn)符號(hào)和換行符
     text = re.sub(r'[^\w ]', ' ', text)
     # 轉(zhuǎn)為小寫
     text = text.lower()

     # 生成所有單詞的列表
     word_list = text.split(' ')

     # 去除空白單詞
     word_list = filter(None, word_list)

     # 生成單詞和詞頻的字典
     word_cnt = {}
     for word in word_list:
         if word not in word_cnt:
            word_cnt[word] = 0
            word_cnt[word] += 1

     # 按照詞頻排序
     sorted_word_cnt = sorted(word_cnt.items(), key=lambda kv: kv[1], reverse=True)

     return sorted_word_cnt
with open('in.txt', 'r') as fin:
    text = fin.read()
word_and_freq = parse(text)
with open('out.txt', 'w') as fout:
   for word, freq in word_and_freq:
       fout.write('{} {}\n'.format(word, freq))

07 | 修煉基本功:條件與循環(huán)

不過吭露,切記讲竿,在實(shí)際寫代碼時(shí)弄屡,我們鼓勵(lì),除了 boolean 類型的數(shù)據(jù)迈嘹,條件判斷最好是顯 性的全庸。比如壶笼,在判斷一個(gè)整型數(shù)是否為 0 時(shí),我們最好寫出判斷的條件:

if i != 0:
 ...
 
#不推薦的寫法:
if i:
...

l = [1, 2, 3, 4, 5, 6, 7]
for index, item in enumerate(l):
    if index < 5:
        print(item) 

在循環(huán)語句中挑豌,我們還常常搭配 continue 和 break 一起使用。所謂 continue氓英,就是讓程 序跳過當(dāng)前這層循環(huán)铝阐,繼續(xù)執(zhí)行下面的循環(huán);而 break 則是指完全跳出所在的整個(gè)循環(huán) 體练对。在循環(huán)中適當(dāng)加入 continue 和 break吹害,往往能使程序更加簡潔、易讀螺男。

range() 函數(shù)是直接由 C 語言寫的下隧,調(diào)用它速度非澄矫剑快。而 while 循環(huán)中的“i += 1”這個(gè)操作土辩,得通過 Python 的解釋器間接調(diào)用底層的 C 語言宗弯;并且這個(gè)簡單的操 作搂妻,又涉及到了對象的創(chuàng)建和刪除(因?yàn)?i 是整型,是 immutable邓厕,i += 1 相當(dāng)于 i = new int(i + 1))详恼。所以引几,顯然,for 循環(huán)的效率更勝一籌敞掘。

08 | 異常處理:如何提高程序的穩(wěn)定性?

class MyInputError(Exception):
 """Exception raised when there're errors in input"""
     def __init__(self, value): # 自定義異常類型的初始化
        self.value = value
     def __str__(self): # 自定義異常類型的 string 表達(dá)形式
        return ("{} is invalid input".format(repr(self.value)))

try:
    raise MyInputError(1) # 拋出 MyInputError 這個(gè)異常
except MyInputError as err:
    print('error: {}'.format(err))

異常更扁,通常是指程序運(yùn)行的過程中遇到了錯(cuò)誤浓镜,終止并退出劲厌。我們通常使用 try except 語句去處理異常,這樣程序就不會(huì)被終止相叁,仍能繼續(xù)執(zhí)行辽幌。 處理異常時(shí),如果有必須執(zhí)行的語句虑润,比如文件打開后必須關(guān)閉等等拳喻,則可以放在 finally block 中猪腕。 異常處理,通常用在你不確定某段代碼能否成功執(zhí)行亚亲,也無法輕易判斷的情況下腐缤,比如數(shù) 據(jù)庫的連接、讀取等等惜索。正常的 flow-control 邏輯,不要使用異常處理剃浇,直接用條件語 句解決就可以了巾兆。

09 | 不可或缺的自定義函數(shù)

def find_largest_element(l):
    if not isinstance(l, list):
        print('input is not type of list')
    return

if len(l) == 0:
    print('empty input')
    return
    largest_element = l[0]
    for item in l:
        if item > largest_element:
            largest_element = item
    print('largest element is: {}'.format(largest_element))

find_largest_element([8, 1, -3, 2, 0])
# 輸出
# largest
# element is: 8

def outer():
    x = "local"

    def inner():

        nonlocal x  # nonlocal 關(guān)鍵字表示這里的 x 就是外部函數(shù) outer 定義的變量 x
    x = 'nonlocal'
    print("inner:", x)
    inner()
    print("outer:", x)

outer()
# 輸出
inner:
nonlocal
outer:
nonlocal

def nth_power(exponent):
    def exponent_of(base):
        return base ** exponent

    return exponent_of  # 返回值是 exponent_of 函數(shù)


square = nth_power(2)  # 計(jì)算一個(gè)數(shù)的平方
cube = nth_power(3)  # 計(jì)算一個(gè)數(shù)的立方
# square
# # 輸出
# < function
# __main__.nth_power. < locals >.exponent(base) >
# cube
# # 輸出
# < function
# __main__.nth_power. < locals >.exponent(base) >
# print(square(2))  # 計(jì)算 2 的平方
# print(cube(2))  # 計(jì)算 2 的立方
# # 輸出
# 4  # 2^2
# 8  # 2^3

  1. Python 中函數(shù)的參數(shù)可以接受任意的數(shù)據(jù)類型角塑,使用起來需要注意,必要時(shí)請?jiān)诤瘮?shù)開 頭加入數(shù)據(jù)類型的檢查质帅;
  2. .和其他語言不同留攒,Python 中函數(shù)的參數(shù)可以設(shè)定默認(rèn)值炼邀;
  3. 嵌套函數(shù)的使用,能保證數(shù)據(jù)的隱私性洛退,提高程序運(yùn)行效率杰标;
  4. 合理地使用閉包,則可以簡化程序的復(fù)雜度媒区,提高可讀性掸犬。

10 | 簡約不簡單的匿名函數(shù)

函數(shù) map(function, iterable) 的第一個(gè)參數(shù)是函數(shù)對象湾碎,第二個(gè)參 數(shù)是一個(gè)可以遍歷的集合呻顽,它表示對 iterable 的每一個(gè)元素贩挣,都運(yùn)用 function 這個(gè)函數(shù)裕便。

python3 -mtimeit -s'xs=range(1000000)' 'map(lambda x: x*2, xs)'
# 2000000 loops, best of 5: 171 nsec per loop
python3 -mtimeit -s'xs=range(1000000)' '[x * 2 for x in xs]'
# 5 loops, best of 5: 62.9 msec per loop
python3 -mtimeit -s'xs=range(1000000)' 'l = []' 'for i in xs: l.append(i * 2)'
# 5 loops, best of 5: 92.7 msec per loop

filter(function, iterable) 函數(shù)下翎,它和 map 函數(shù)類似庆揩,function 同樣表示一個(gè) 函數(shù)對象锈拨。filter() 函數(shù)表示對 iterable 中的每個(gè)元素验辞,都使用 function 判斷壳贪,并返回 True 或者 False磕蒲,最后將返回 True 的元素組成一個(gè)新的可遍歷的集合殖卑。

l = [1, 2, 3, 4, 5]
new_list = filter(lambda x: x % 2 == 0, l) # [2, 4]

最后我們來看 reduce(function, iterable) 函數(shù),它通常用來對一個(gè)集合做一些累積操作荣刑。 function 同樣是一個(gè)函數(shù)對象董习,規(guī)定它有兩個(gè)參數(shù)皿淋,表示對 iterable 中的每個(gè)元素以及上 一次調(diào)用后的結(jié)果恬试,運(yùn)用 function 進(jìn)行計(jì)算,所以最后返回的是一個(gè)單獨(dú)的數(shù)值哑舒。

l = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, l) # 1*2*3*4*5 = 120
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洗鸵,一起剝皮案震驚了整個(gè)濱河市仗嗦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌火邓,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鸣驱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)踊东,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門闸翅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菊霜,“玉大人,你說我怎么就攤上這事鉴逞。” “怎么了构捡?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵勾徽,是天一觀的道長。 經(jīng)常有香客問我喘帚,道長,這世上最難降的妖魔是什么涡匀? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任陨瘩,我火速辦了婚禮级乍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甚淡。我一直安慰自己捅厂,他們只是感情好资柔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布贿堰。 她就那樣靜靜地躺著啡彬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纵搁。 梳的紋絲不亂的頭發(fā)上腾誉,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天峻呕,我揣著相機(jī)與錄音,去河邊找鬼眼耀。 笑死佩憾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的楞黄。 我是一名探鬼主播抡驼,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼致盟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了雷蹂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤匪煌,失蹤者是張志新(化名)和其女友劉穎萎庭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肴敛,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡达舒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年巩搏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贯底。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡禽捆,死狀恐怖胚想,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浊服,我是刑警寧澤胚吁,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布腕扶,位于F島的核電站,受9級(jí)特大地震影響半抱,放射性物質(zhì)發(fā)生泄漏窿侈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一江掩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧策泣,春花似錦抬吟、人聲如沸火本。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽擎析。三九已至,卻和暖如春桨醋,著一層夾襖步出監(jiān)牢的瞬間现斋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工瞬内, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留遂鹊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓秉扑,卻偏偏與公主長得像舟陆,于是被迫代替她去往敵國和親耻矮。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355