day14回顧
異常
語句處理的語句
try-except 語句
捕獲錯誤通知,把程式的異常狀态改回正常狀态
try-finally 語句
執行在正常流程和異常流程下都必須要執行的語句
raise 語句
抛出(觸發) 錯誤通知,讓程式進入到異常流程
assert 語句(斷言語句)
根據條件,決定是否抛出AssertionError類型的錯誤
疊代器
iter(obj) 用obj這個可疊代對象傳回obj的疊代器
next(疊代器) 向疊代器要資料,當沒有資料時會收到
StopIteration異常通知
s = "hello"
it = iter(s)
print(next(it)) # h
print(next(it)) # e
新的一天
什麼是生成器:
生成器是能夠動态提供資料的可疊代對象
生成器是在程式運作時生成資料,與容器類不同,它通常不會在記憶體中
儲存大量的資料,而是現用現生成
生成器有兩種:
生成器函數
生成器表達式
生成器函數:
含有yield 語句的函數是生成器函數,此函數被調用将傳回一個生成
器對象
yield 翻譯為(産生或生成)
yield 語句
文法:
yield 表達式
說明:
yield 隻能用于def 函數中,目的是将此函數作為生成器函數使用
yield 用來生成資料,供疊代器的next(it) 函數使用
示例見:
```
def myyield():
print("即将生成2")
yield 2
print("即将生成3")
yield 3
print('生成器函數調用結束')
g = myyield() # g綁定的是一個生成器,生成器是可疊代對象
print("g綁定的是:", g) # g=<generator object ...at >
it = iter(g) # it 綁定g的疊代器
v = next(it)
print('v=', v) # v=2
v2 = next(it)
print('v2=', v2) # v2=3
v3 = next(it) # 觸發StopIteration異常
print('v3=', v3)
```
說明:
生成器函數的調用将傳回一個生成器對象,生成器對象是一個可疊
代對象
生成器函數調用return會觸發一個StopIteration異常(即生成
資料結束)
示例2見:
```
def myinteger(n):
i = 0
while i < n:
yield i
i += 1
L = []
for x in myinteger(30000000000000000):
# print(x) # 列印 0, 1, 2
L.append(x)```
練習:
寫一個生成器函數 myeven(start, stop) 用來生成從start開始
到stop結束(不包含stop)區間内的一系列偶數
如:
def myeven(start, stop):
for i in range(start,stop):
if i%2==0:
yeild i
events = list(myeven(10, 20))
print(events) # [10, 12, 14, 16, 18]
for x in myeven(21, 30):
print(x) # 列印: 22 24 26 28
L = [x**2 for x in myeven(1, 10)]
print(L) # [4, 16, 36, 64]
生成器表達式:
文法:
( 表達式 for 變量 in 可疊代對象 [if 真值表達式] )
說明:
if 子句部分可以省略
作用:
用推導式形式建立一個新的生成器
示例:
gen = (x**2 for x in range(1, 5))
it = iter(gen)
next(it) # 1
next(it) # 4
next(it) # 9
next(it) # 16
next(it) # StopIteration
練習:
1. 已知有清單:
L = [2, 3, 5, 7]
1) 寫一個生成器函數,讓此函數能夠動态的提供資料,資料為原
清單的數字的平方加1
def func(L):
for i in L:
yeild i**2+1
2) 寫一個生成器表達式,讓此表達式能夠動态提供資料,資料為原
清單的數字的平方加1
L = (X**2+1 for x in L)
3) 生成一個清單,此清單的資料為原清單的數字的平方加1
說明:
生成器函數或生成器表達式調用後傳回的生成器,
即是生成器也是疊代器
示例:
gen = (x**2 for x in range(3))
it = iter(gen) # 向生成器擷取疊代器,但傳回的是gen
next(it) # 0
next(gen) # 1
next(it) # 4
next(gen) # StopIteration
示例:
numbers = [10086, 10000, 10010, 95588]
names = ['中國移動', '中國電信', '中國聯通']
for t in zip(numbers, names):
print(t) # (10086, '中國移動'), (10000, '中國電信')
d = dict(zip(numbers, names))
print(d) # {10086: '中國移動', 10000:'中國電信', ...}
for t in zip(names, numbers, range(1, 1000)):
print(t) # ('中國移動', 10086, 1), (...)
用生成器函數實作myzip函數來代替zip函數,示例見:
```
# 此示例示意自己定義生成器函數myzip來替代zip函數
# def myzip(*args):
def myzip(iter1, iter2):
it1 = iter(iter1) # 拿到iter1的疊代器
it2 = iter(iter2) # 拿到iter2的疊代器
while True:
try:
x = next(it1) # 取出元組的第一個元素
y = next(it2) # 取出第二個元素
yield (x, y)
except StopIteration:
return
# def myzip(iter1, iter2):
# it1 = iter(iter1) # 拿到iter1的疊代器
# it2 = iter(iter2) # 拿到iter2的疊代器
# while True:
# x = next(it1) # 取出元組的第一個元素
# y = next(it2) # 取出第二個元素
# yield (x, y)
numbers = [10086, 10000, 10010, 95588]
names = ['中國移動', '中國電信', '中國聯通']
for t in myzip(numbers, names):
print(t) # (10086, '中國移動'), (10000, '中國電信')
```
enumerate 函數
- 函數格式:
enumerate(iterable, start=0)
作用:
生成一個枚舉可疊代對象,此可疊代對象生成類型為(索引,值)的
元組,,預設索引從0開始,也可以用start指定
示例:
names = ['中國移動', '中國電信', '中國聯通']
for t in enumerate(names):
print(t) # (0, '中國移動'), (1, '中國電信), (...)
練習:
自己寫一個與enumerate功能相同的生成器函數myenumerate
如:
def myenumerate(...):
...
names = ['中國移動', '中國電信', '中國聯通']
for t in myenumerate(names):
print(t) # (0, '中國移動'), (1, '中國電信), (...)
for t in myenumerate(names, 100):
print(t) # (100, '中國移動'), (101, '中國電信), (...)
序列:
字元串str, 清單list, 元組tuple, 位元組串bytes,
位元組數組bytearray
位元組串bytes(也叫做位元組序列)
作用:
存儲以位元組為機關的資料,
說明:
位元組串是不可以改變的序列
位元組是0~255之間的整數,用來表示一個位元組的取值
位元組:
位元組(byte)是以8個位(bit)為機關的存儲單元
0b11111111 --> 255
0b00000000 --> 0
建立空位元組串的字面值:
b''
b""
b''''''
b""""""
建立非空位元組串字面值
b'ABCD'
b"ABCD"
b'\x41\x42\x43\x44'
位元組串的構造函數:
bytes() 生成一個空的位元組串,等同于b''
bytes(整型可疊代對象) 用可疊代對象初始化一個字元串
bytes(整數n) 生成n個值為0的位元組串
bytes(字元串, encode='utf-8') 用字元串的轉換編碼
生成一個位元組串
示例:
B = bytes() # B = b''
B = bytes(range(65, 80)) # B = b'ABCDEF...'
B = bytes(10) # B = b'\x00\x00\x00...'
B = bytes('tarena', 'utf-8') # B=b'tarena'
位元組串的運算
+ += * *=
< <= > >= == !=
in , not in
索引index 和 切片
注: 位元組串為不可變類型,隻能索引和切片取值,不能指派
示例:
b = b'ABC' + b'123' # b = b'ABC123'
b = b'ABC' * 3 # b=b'ABCABCABC'
b'ABC' > b'AB' # True
65 in b'ABC' # True
b = b'ABCDEFG'
print(b[0]) # 65
print(b[::2]) # b'ACEG'
内建函數:
len(x), max(x), min(x), sum(x), any(x), all(x)
bytes 和 str 的差別:
bytes 存儲位元組(0~255的整數)
str 存儲unicode字元(0~0x10FFFF的整數)
str 與 bytes 的轉換
編碼(encode)
str -----------> bytes
b = s.encode(encoding='utf-8')
解碼(decode)
bytes -----------> str
s = b.decode(encoding='utf-8')
示例:
s = "hello中國"
b = s.encode() # 等同于 s.encode('utf-8')
# b = b'hello\xe4\xb8\xad\xe5\x9b\xbd'
s2 = b.decode() # s2 = 'hello中國'
位元組數組 bytearray
可變的位元組序列
建立位元組數組的構造函數 bytearray
bytearray() 建立空的位元組數組
bytearray(整數n) 建立n個值為0的位元組數組
bytearray(整型可疊代對象) 用可疊代對象初始化一個位元組數組
bytearray(字元串,encoding='utf-8') 用字元串的轉換編碼
生成一個位元組數組
運算符:
+ += * *=
< <= > >= == !=
in, not in
索引和切片:
注: 位元組數組支援索引和切片指派,規則同清單的索引和切片
指派規則
位元組數組的方法見:
文檔參見:
方法 說明
B.clear() 清空
B.append(n) 追加一個位元組(n為0-255的整數)
B.remove(value) 删除第一個出現的位元組,如果沒有出現,則産生ValueError錯誤
B.reverse() 位元組的順序進行反轉
B.decode(encoding='utf-8')
B.find(sub[, start[, end]])
練習:
寫一個程式,從鍵盤輸入一段字元串,用變量s綁定
s = input()
b = s.encode("utf-8")
print(len(s))
print(len(b))
s2 = b.decode("utf-8")
print(s==s2)
1. 将此字元串轉為位元組串用變量b綁定,并列印出來
2. 列印出字元串s的長度和位元組串b的長度
3. 将b位元組串再轉換為字元串用變量s2綁定,再判斷s2與s是否相同
練習:
1. 看下列函數的輸出結果是什麼? 為什麼?
第一個程式:
L = [2, 3, 5, 7]
A = [x * 10 for x in L]
it = iter(A)
print(next(it)) # ????
L[1] = 333
print(next(it)) # ????
第二個程式:
L = [2, 3, 5, 7]
A = (x * 10 for x in L)
it = iter(A)
print(next(it)) # 20
L[1] = 333
print(next(it)) # 30
2. 試寫一個myfilter函數,要求此函數與内建的filter函數的功能
一緻
如:
def myfilter(fn, iterable):
for x in iterable:
if fn(x):
yield x
for x in myfilter(lambda x: x%2==1, range(10)):
print(x) # 1 3 5 7 9
3. 寫一個生成器函數myxrange([start, ] stop[, step]) 來
生成一系列整數,
要求:
myxrange功能與range功能完全相同
不允許調用range函數和清單
```
def myxrange(start, stop=None, step=None):
if stop is None:
stop = start
start = 0
if step is None:
step = 1
# 正向
if step > 0:
while start < stop:
yield start
start += step
# 反向
else:
while start > stop:
yield start
start += step # 加上負的步長
for x in myxrange(3):
print(x)
for x in myxrange(100, 103):
print(x)
for x in myxrange(1000, 1010, 3):
print(x)
for x in myxrange(10, 0, -3):
print(x)
```
4. 預習:
檔案 和 面向對象程式設計
5. 分解質因數,輸入一個正整數,分析質因數
如
```
def get_zhiyinshu(x):
'''如x=90
傳回: [2, 3, 3, 5]
'''
L = []
while x > 1: # 它一定至少有一個質因數
for i in range(2, x + 1):
if x % i == 0: # i為x的質因數
L.append(i)
# 修改正x的下一次的值
x = int(x / i)
break # 終止本次打開
return L
n = int(input("請輸入一個整數: "))
L = get_zhiyinshu(n)
L2 = [str(x) for x in L]
s = str(n) + '=' + '*'.join(L2)
print(s)
```
輸入: 90
列印:
90 = 2*3*3*5
(質因數是的指最小能被原數整除的系數(不包括1))