1. 程式人生 > 其它 >Python基礎 - 06推導式及生成器

Python基礎 - 06推導式及生成器

Python基礎 - 06推導式及生成器

一、列表推導式

格式: [表示式for變數in舊列表] [表示式for變數 in舊列表if條件]

names = ['tom', 'lily', 'abc', 'Hello', 'Jack', 'lucy']
result1 = [name for name in names if len(name) > 3]
print(result1)                     # ['lily', 'Hello', 'Jack', 'lucy']

result2 = [name.capitalize() for name in names if len(name) <= 3]
print(result2)                     # ['Tom', 'Abc']

# 將1-100之間被3整除的數字組成一個列表
result3 = [num for num in range(1, 101) if num % 3 == 0]
print(result3)

result4 = [num for num in range(1, 101) if num % 3 == 0 and num % 5 == 0]
print(result4)

# 0-5 偶數 0-10 奇數 (0,1) (0,3) ... (0,9) (2,1) (2,3) ... result5 = [(x, y) for x in range(5) if x % 2 == 0 for y in range(10) if y % 2 != 0] print(result5)

  

employee1 = {'name': 'zhangsan', 'salary': 4300}
employee2 = {'name': 'lisi', 'salary': 5500}
emp = [employee1, employee2]
n = [employee['salary'] + 200 if
employee['salary'] > 4500 else employee['salary'] + 500 for employee in emp] print(n) # [4800, 5700]

  

二、字典推導式、集合推導式

list1 = [1, 2, 3, 1, 5, 3, 2, 6, 8, 9, 8, 8, 9]
set1 = {x - 1 for x in list1 if x > 5}       # 類似列表推導式,沒有重複元素
print(set1)                                  # {8, 5, 7}

dict1 = {'k1': 'v1', 'k2': 'v2'}
newdict = {value: key for key, value in dict1.items()
} print(newdict) # {'v1': 'k1', 'v2': 'k2'}

  

三、生成器

使用列表推導式生成列表,但受到記憶體限制,容量有限。建立一個100萬元素的列表,僅僅需要訪問前面幾個元素,造成空間浪費。

邊迴圈邊計算的機制,稱為生成器,generator

next(generator):每次呼叫都會產生一個新的元素,如果元素都產生完畢,再次呼叫會產生異常。

生成器方法:g.__next__() g.send(value)

3.1定義生成器

list2 = [x * 3 for x in range(10)]
print(type(list2))                 # <class 'list'>

g = (x * 3 for x in range(5))
print(type(g))                     # <class 'generator'>
print(g)                           # <generator object <genexpr> at 0x000000DC2790DF90>
print(g.__next__())                # 0
print(g.__next__())                # 3
print(g.__next__())                # 6
print(next(g))                     # 9
print(next(g))                     # 12
#print(next(g))                    # StopIteration

3.2使用try...except結構讀取生成器元素;讀取讀取的方式 next(g)或g.__next__()  

while True:
    try:
        e = next(g)
        print(e)
    except:
        print('沒有元素啦')
        break
print('測試結束')
'''
0
3
6
9
12
沒有元素啦
測試結束
'''

3.3定義生成器方式:函式  

# 定義生成器方式二: 函式
# 只要函式中出現yield關鍵字,則函式不再是函式,變成生成器了。
def func6():
    n = 0
    while True:
        n += 1
        # print(n)
        yield n      # 效果等同於  return n + 暫停

g = func6()

print(g)         # <generator object func6 at 0x0000008356E8DF20>
print(next(g))   # 1
print(next(g))   # 2

  

使用生成器實現斐波那契數列:

def fib(length):
    a, b = 0, 1
    n = 0
    while n < length:
        yield b
        a, b = b, a + b
        n += 1

g = fib(8)
print(next(g))  # 1
print(next(g))  # 1
print(next(g))  # 2
print(next(g))  # 3
print(next(g))  # 5
print(next(g))  # 8
print(next(g))  # 13
print(next(g))  # 21
def fib(length):
    a, b = 0, 1
    n = 0
    while n < length:
        print(b)
        a, b = b, a + b
        n += 1

fib(8)  # 也能實現輸出 1 1 2 3 5 8 13 21

3.4生成器帶return語句 

def fib(length):
    a, b = 0, 1
    n = 0
    while n < length:
        yield b
        a, b = b, a + b
        n += 1

    return 'abc'

g = fib(8)
print(next(g))  # 1
print(next(g))  # 1
print(next(g))  # 2
print(next(g))  # 3
print(next(g))  # 5
print(next(g))  # 8
print(next(g))  # 13
print(next(g))  # 21
print(next(g))  # StopIteration: abc ;沒有 return時,報錯StopIteration

3.5send方法:向生成器中傳值 

def gen():
    i = 0
    while i < 5:
        temp = yield i
        print('temp: ', temp)
        i += 1
    return '沒有資料了'

g = gen()
print(g.__next__())  # 0
print(g.__next__())  # temp:  None  \n  1
print(g.__next__())  # temp:  None  \n  2
n1 = g.send('呵呵') print('n1: ', n1) # temp: 呵呵 \n n1: 3 n2 = g.send('哈哈') print('n2: ', n2) # temp: 哈哈 \n n2: 4 n3 = g.send(None) # temp: None \n StopIteration: 沒有資料了, 取值時沒有了報錯,賦值成功 print('n3: ', n3) # 這個沒有執行

直接往生成器非None傳值報錯

g = gen()

# print(g.__next__())  
# print(g.__next__())  
# print(g.__next__())  
n1 = g.send('呵呵')
# 報錯:
# TypeError: can't send non-None value to a just-started generator
g = gen()

print(g.send(None))     #  改成   n = g.send(None) 也可以
n1 = g.send('呵呵')
print('n1: ', n1)   
'''
0
temp:  呵呵
n1:  1
'''

  

def gen1():
    i = 0
    while i < 5:
        temp = yield i
        print('temp: ', temp)
        for i in range(temp):
            print('------->', i)
        print('**************')
        i += 1
    return '沒有資料了'

g1 = gen1()
print(g1.send(None))
n1 = g1.send(3)
print('n1:',n1)
'''
0
temp:  3
-------> 0
-------> 1
-------> 2
************** 
n1: 3
'''

n2 = g1.send(4)
print('n2:', n2)
'''
temp:  4
-------> 0
-------> 1
-------> 2
-------> 3
**************
n2: 4
'''

  

def task1(n):
    for i in range(n):
        print('正在搬第{}塊磚'.format(i+1))
        yield None

def task2(n):
    for i in range(n):
        print('正在聽第{}首歌'.format(i+1))
        yield None

g1 = task1(3)
g2 = task2(2)


while True:
    g1.__next__()
    g2.__next__()

'''
正在搬第1塊磚
正在聽第1首歌
正在搬第2塊磚
正在聽第2首歌
正在搬第3塊磚
Traceback (most recent call last):
  File "E:\PythonLearn\pythonBase\02door2\08-generator-03.py", line 23, in <module>
    g2.__next__()
StopIteration
'''

處理異常:  

while True:
    try:
        g1.__next__()
        g2.__next__()
    except:
        pass

3.6可迭代與迭代器  

# 可迭代的物件   1. 生成器            2. 元祖 列表 集合 字典 字串
# 如何判斷一個物件是否可迭代

from collections import Iterable

list1 = [1,2,46,5,3]
result = isinstance(list1, Iterable)
print(result) # True

result = isinstance('abc', Iterable)
print(result) # True

result = isinstance(100, Iterable)
print(result) # False

  

迭代是訪問集合元素的一種方式。迭代器是一個可以記住遍歷位置的物件。

迭代器物件從集合的第一個元素開始訪問,直到所有元素都被訪問完結束。迭代器只能往前不會後退。

# 可以被next()函式呼叫並返回下一個值的物件稱為迭代器:Iterable。
# 可迭代的 不一定就是迭代器。
# 生成器是可迭代的,是迭代器。 list是可迭代的,但不是迭代器。
list1 = iter(list1)
print(next(list1)) # 1
print(next(list1)) # 2