天天看點

Python進階特性——為什麼都說Python高效Python的進階特性

Python的進階特性

——為什麼都說Python高效

由于文章含有大量代碼,

在微信公衆号中閱讀不友善,

是以我也将全文放在我的網站中,

有更加酷炫的背景和代碼高亮,

大家可以直接點選原文檢視喲!

作者:Beyond

時間:2018-9-29

本微教程根據廖雪峰python教程中的部分内容,配合我個人的學習經曆進行總結整理。

分為以下四個部分:

  1. 神奇的切片——高效擷取清單中想要的元素
  2. 可疊代對象--清單、元組、字典等到底啥差別
  3. 清單生成器--複雜的list,一行代碼生成
  4. 生成器/疊代器--generator、yield到底什麼鬼

1.神奇的切片

l = list(range(20))
print(l)           

複制

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]           

複制

## 取出前3項,後3項,第6到第11項,倒數第2個到倒數第5個:
first_3 = l[:3]
last_3 = l[-3:]
middle = l[5:11] # 指從l[5]到l[10],共11-5=6項
last_2_5 = l[-5:-1] # 指從l[-5]到l[-2],共-1-(-5)=4項
print("1:",first_3,"\n2:",last_3,"\n3:",middle,"\n4:",last_5_2)           

複制

1: [0, 1, 2] 
2: [17, 18, 19] 
3: [5, 6, 7, 8, 9, 10] 
4: [15, 16, 17, 18]           

複制

## 每1項、每2項、每3項取出一個:
l_1 = l[::1]
l_2 = l[::2]
l_3 = l[::3]
print("1:",l_1,"\n2:",l_2,"\n3:",l_3)
## 分别取出奇數項、偶數項:
l_odd = l[1::2] # 即,從第一項開始取,每兩項取一個
l_even = l[::2]
print("---\nl的奇數項:\n",l_odd,"\nl的偶數項:\n",l_even)
## 取出前10項中的奇數:l_first10_odd = l[1:10:2]
print("\n前10項中的奇數:\n",l_first10_odd)           

複制

1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 
2: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 
3: [0, 3, 6, 9, 12, 15, 18]
---
l的奇數項:
 [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] 
l的偶數項:
 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

前10項中的奇數:
 [1, 3, 5, 7, 9]           

複制

2.可疊代對象

list、tuple、dict、string在python中都是可疊代對象,是以都可以用for來周遊。

l = [10,20,30,40]
t = (10,20,30,40)
d = {"a":1,"b":2,"c":3,"d":4,"e":5,"f":6}
s = "Hello python!"for each in s:
    print(each,end=' ')
print()for each in d:
    print(each,end=' ')
print("\n注意到,直接列印dict的每一項,輸出的隻是【鍵】!")           

複制

H e l l o   p y t h o n ! 
a b c d e f 
注意到,直接列印dict的每一項,輸出的隻是【鍵】!           

複制

## 如果想單獨擷取dictionary的鍵或者值的清單,可以這樣:

items = list(d.items())
keys = list(d.keys())
values = list(d.values())
print(items,"\n",keys,"\n",values)           

複制

[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6)] 
 ['a', 'b', 'c', 'd', 'e', 'f'] 
 [1, 2, 3, 4, 5, 6]           

複制

## 如果想擷取可疊代對象每一項的序号,可以使用enumerate函數:

for index,value in enumerate(l):
    print(index," : ",value)           

複制

0  :  10
1  :  20
2  :  30
3  :  40           

複制

3.一行代碼生成清單——清單生成式

  • 基礎版:對原list直接進行變換
  • 進階版:添加一個條件if,甚至if…else…
l = list(range(10))
print(l)           

複制

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]           

複制

## 生成l的每一項的平方的新清單:

l_square = [x*x for x in l]
print(l_square)           

複制

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]           

複制

## 在上面的基礎上,加一個條件:要求元素大于30:
l_square_above30 = [x*x for x in l if x*x>30]
print(l_square_above30)           

複制

[36, 49, 64, 81]           

複制

## 再玩一個更加複雜的,把l轉換成:能被2整除的變為1,否則變為0:
l_devideby2 = [1 if x%2==0 else 0 for x in l]
print(l_devideby2)           

複制

[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]           

複制

"""
練習:
我們有一列名字,但是都沒有首字母大寫:
names = ['david','adam','davis','bob','alice','judy','kate','djangh'].
我們希望把首字母都大寫,顯示首字母是d的所有名字,其餘的名字變為'---'.
"""

names = ['david','adam','davis','bob','alice','judy','kate','djangh']
selected = [name.capitalize() if name[0]=='d' else '---' for name in names]
print(selected)           

複制

['David', '---', 'Davis', '---', '---', '---', '---', 'Djangh']           

複制

4.生成器 generator

生成器是python的進階特性之一,我們經常聽說這個詞,但是一直都挺陌生的,而且平常寫一寫小型程式,做一些小項目,也許根本涉及不到這個玩意兒。是以,生成器存在的意義是什麼?

一般情況下,我們存儲一串資料,都是放在一個list裡面,比方說,我們要讀取一個文本,然後分詞,把分詞的結果放進一個list裡面。如果檔案很大的話,那相當于我們直接把這麼大的一個東西存到了我們的記憶體中,這樣會迅速加大計算機的負荷,影響我們的計算效率,甚至直接memory out了。

但是很多時候,我們并不是一次性就要使用所有資料,而是每次隻用一小部分,那我們完全可以需要的時候,根據某種規則或者算法把要用的資料讀進記憶體,用完就丢掉。這樣,我們就不用建立完整的list,節省了記憶體。這種方法,我們成為生成器(generator)。

最簡單建立一個generator的方法是,把清單生成器的[]改成():

simple_generator = (x for x in l)
simple_generator           

複制

<generator object <genexpr> at 0x000000DA987B65C8>           

複制

for i in simple_generator:
    print(i,end=' ')## 或者可以調用next(generator)方法:

    try:
        next(simple_generator)
    except StopIteration as e:
        print("\n疊代器已經輸出所有元素,不能繼續疊代!")
        print("Error info:",e.value)           

複制

0 1 2 3 4 5 6 7 8 9 
疊代器已經輸出所有元素,不能繼續疊代!
Error info: None           

複制

另一種方法就是寫一個函數,把想要疊代得到的值通過yield輸出(本來輸出是print,我們改成yield),這樣,這個函數就變成了一個generator:

def fib(max):
    n,a,b, = 0,0,1
    while(n<max):        
        yield a
        a,b = b,a+b
        n += 1
    return "Done!"           

複制

for i in fib(50):
    print(i,end=' ')           

複制

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465 14930352 24157817 39088169 63245986 102334155 165580141 267914296 433494437 701408733 1134903170 1836311903 2971215073 4807526976 7778742049            

複制

"""
來一個難度更大一點的,輸出楊輝三角形:
          1
         / \
        1   1
       / \ / \
      1   2   1
     / \ / \ / \
    1   3   3   1
   / \ / \ / \ / \
  1   4   6   4   1
 / \ / \ / \ / \ / \
1   5   10  10  5   1
要求得到一個generator,每次輸出三角形的一行。

"""

# 方法1:
# 根據規律,可以看出,第一行第二行分别是[1]和[1,1]
# 到了第三行,把頭尾的兩個1去掉,中間的部分,就是由上一行去頭與上一行去尾的和得到的
# 是以可以寫如下函數:

def yanghui_triangle():
    l = [1]
    i = 0
    while(True):        
        if len(l)==1:            
            yield l
            l = [1,1]        
        else:            
            yield l
            l = [x+y for x,y in zip(l[:-1],l[1:])]
            l.insert(0,1)
            l.append(1)           

複制

g = yanghui_triangle()
print(g)           

複制

<generator object yanghui_triangle at 0x00000085F970AFC0>           

複制

for i in range(10):
    print(next(g))           

複制

[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]           

複制

# 方法2:
# 用最原始的規律,從三角形可以看出,每一項,都是上一行對應兩項之和;
# 但是直接用上一行的元素去相加,似乎少了點什麼,
# 這個時候我們發現,如果在每一行後面添加一個0,那麼就可以解決這個問題:
def yanghui_triangle2():
    l = [1]    
    while(True):        
        yield l
        l.append(0)  ## 增加一個長度
        l = [l[i-1]+l[i] for i in range(len(l))]        
        ## l[-1]恰好是0,最後兩項之和恰好是之前的最後一項           

複制

g2 = yanghui_triangle2()
print(g2)           

複制

<generator object yanghui_triangle2 at 0x00000085F9972BF8>           

複制

for i in range(10):
    print(next(g2))           

複制

[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]           

複制

總結:

從上面的四個部分,我們可以深刻感受到Python的簡潔。

例如,我們通過清單生成式,可以把原本需要用for循環,再加上if...else...等等結構才能生成的一個清單,用一行代碼就表示出來了,而且邏輯很清晰。

我們在實際程式設計的時候,應該盡可能多思考,如何利用Python的進階特性,讓代碼更簡潔更高效。