python高階特性:切片/迭代/列表生成式/生成器

楊俊明發表於2018-04-22

廖雪峰老師的教程上學來的,地址:python高階特性 

下面以幾個具體示例演示用法:

一、切片

1.1 利用切片實現trim

def trim(s):
    while s[:1] == " " or s[-1:] == " ": # 若第1個元素或最後1個元素為空格
        if s[:1] == " ":
            s = s[1:]
        if s[-1:] == " ":
            s = s[:-1]
    return s

注:字串可以看做一個list,列表切片的完整寫法是 L[start:end],其中end也支援負數,最後一個數用-1表示,第1個數用0表示,如果省略start,表示從0開始,如果省略end,表示到最後1個元素結束。

測試程式碼:

if trim(`hello  `) != `hello`:
    print(`測試失敗1!`)
elif trim(`  hello`) != `hello`:
    print(`測試失敗2!`)
elif trim(`  hello  `) != `hello`:
    print(`測試失敗3!`)
elif trim(`  hello  world  `) != `hello  world`:
    print(`測試失敗4!`)
elif trim(``) != ``:
    print(`測試失敗5!`)
elif trim(`    `) != ``:
    print(`測試失敗6!`)
else:
    print(`測試成功!`)

1.2 切片還有第3個引數,即:L[start:end:skip],比如在1-10之間,把奇數、偶數選出來

list_1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

odd = list_1[::2]
even = list_1[1::2]

print(odd)
print(even)

輸出:

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

 

二、迭代

list_1 = list(range(1, 11))

print("正向迭代:")
for x in list_1:
    print(x)

print("
反向迭代:")
for x in reversed(list_1):
    print(x)

print(`
帶索引的迭代:`)
for m in enumerate(list_1):
    print("list_1[", m[0], "]=", m[1])

dic_1 = {"name": "菩提樹下的楊過", "blog": "http://yjmyzz.cnblogs.com/"}

# 字典的迭代
print("
dict字典迭代1:")
for k in dic_1:
    print("key:", k, ",value:", dic_1[k])

print("
dict字典迭代2:")
for v in dic_1.values():
    print("value:", v)

print(`
dict字典迭代3:`)
for k, v in dic_1.items():
    print("key:", k, ",value:", v)

輸出:

正向迭代:
1
2
3
4
5
6
7
8
9
10

反向迭代:
10
9
8
7
6
5
4
3
2
1

帶索引的迭代:
list_1[ 0 ]= 1
list_1[ 1 ]= 2
list_1[ 2 ]= 3
list_1[ 3 ]= 4
list_1[ 4 ]= 5
list_1[ 5 ]= 6
list_1[ 6 ]= 7
list_1[ 7 ]= 8
list_1[ 8 ]= 9
list_1[ 9 ]= 10

dict字典迭代1:
key: name ,value: 菩提樹下的楊過
key: blog ,value: http://yjmyzz.cnblogs.com/

dict字典迭代2:
value: 菩提樹下的楊過
value: http://yjmyzz.cnblogs.com/

dict字典迭代3:
key: name ,value: 菩提樹下的楊過
key: blog ,value: http://yjmyzz.cnblogs.com/

  

三、列表生成器

這個老厲害了!比如:要找出1~100內所有奇數的平方數(即:1,3,5… 這些數的平方數)

a = [x ** 2 for x in range(1, 101) if x % 2 == 1 and x ** 2 <= 100]
print(a)

輸出:[1, 9, 25, 49, 81]

再比如,列印出當前目錄下的所有檔案(不考慮遞迴子目錄) 

import os

print([f for f in os.listdir(".")])

小結:寫法就是 [… for … in .. if …] ,要生成的list項寫在for前面,如果迭代時需要指定條件,寫在最後的if中。

 

四、生成器(generator)

這是python引入的一個新概念,想想剛才學到的列表生成器:

result1 = [x ** 2 for x in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
print(type(result1), result1)

輸出:

<class `list`> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

不知道大家想過沒有:如果for前面的運算比較複雜(比如:求平方根),而for迭代的列表又很大(比如:1千萬個),最終列表生成器肯定執行很慢,會嚴重影響效能。能不能做到『延時』計算?等到真正要用的時候,再按需計算。這就是生成器(generator)要解決的問題,它與[列表生成器]的區別在於,它只儲存計算邏輯(即: 儲存演算法),並不馬上計算結果,真正要用的時候,呼叫next(g)取出下一個計算結果即可,當然,它也支援迭代。

generator1 = (x ** 2 for x in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(type(generator1), generator1)

# 取出第1個值
print(next(generator1))
# 取出第2個值
print(next(generator1))

# 列印剩餘的值
for x in generator1:
    print(x)

輸出:

<class `generator`> <generator object <genexpr> at 0x1087e7f10>
1
4
9
16
25
36
49
64
81
100

從輸出型別上看,它的型別是generator,而非list。單純從語法上看,只要把”列表生成器”的[],換成()即可。

再來一個複雜點的示例,中學我們都學過”楊輝三角”,如果用常規思路,列印出楊輝三角,可以參考下面的程式碼:

import copy

def triangles(limit):
    first, second = [1], [1, 1]
    print(first)
    if limit > 1:
        print(second)
        if limit == 2:
            return
        x = copy.copy(second)
        while True:
            y = copy.copy(first)
            [y.append(x[i] + x[i + 1]) for i in range(len(x) - 1)]
            y.append(1)
            print(y)
            x = copy.copy(y)
            if len(y) >= limit:
                return


triangles(10)

輸出:

[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]

如果,要改寫成生成器(generator),該怎麼做呢?答案:只要把print(…)的地方,改成yield 即可。

def triangles_generator(limit):
    first, second = [1], [1, 1]
    yield first
    if limit > 1:
        yield second
        if limit == 2:
            return
        x = copy.copy(second)
        while True:
            y = copy.copy(first)
            [y.append(x[i] + x[i + 1]) for i in range(len(x) - 1)]
            y.append(1)
            yield y
            x = copy.copy(y)
            if len(y) >= limit:
                return


g = triangles_generator(10)
# 取出前2個
print(next(g))
print(next(g))
# 剩下的用迭代寫法輸出
for x in g:
    print(x)

輸出與剛才相同,就不重複貼了。關於這個yield,如果還沒理解的,可以對比看下面的示例:

def test1():
    return [1, 2, 3]


def test2():
    print("test2=>1")
    yield 1
    print("test2=>2")
    yield 2
    print("test2=>3")
    yield 3


print(test1())
g = test2()
print(next(g))
print(next(g))
print(next(g))

輸出:

[1, 2, 3]
test2=>1
1
test2=>2
2
test2=>3
3

test2()遇到yield後,會停下來,儲存現場,等待下一次呼叫next()時,才會繼續執行。

作者:菩提樹下的楊過
出處:http://yjmyzz.cnblogs.com

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。


相關文章