初識生成器python
生成器的本質就是迭代器,在python社區中,大多數時候都把迭代器和生成器是作同一個概念。app
惟一的不一樣就是:函數
迭代器都是Python給你提供的已經寫好的工具或者經過數據轉化得來的,(好比文件句柄,iter([1,2,3])。工具
生成器是須要咱們本身用python代碼構建的工具。最大的區別也就如此了。編碼
生成器的構建方式3d
在 python 中有三種方式來建立生成器:code
生成器函數orm
# 函數: def func(): print(111) return 222 ret = func() print(ret) # 結果: # 111 # 222 # 生成器函數: def func(): print(111) yield 222 ret = func() print(ret) # 結果: # <generator object func at 0x102cd3d00>
將函數中的 return 換成 yield,func 就不是函數了,而是一個生成器函數。對象
因爲函數中存在yield,那麼這個函數就是一個生成器函數.咱們在執行這個函數的時候.就再也不是函數的執行了.而是獲取這個生成器對象ip
生成器的本質就是迭代器.迭代器如何取值,生成器就如何取值。因此咱們能夠直接執行next()來執行如下生成器
def func(): print("111") yield 222 gener = func() # 這個時候函數不會執⾏. ⽽是獲取到⽣成器 ret = next(gener) # 這個時候函數纔會執⾏ print(ret) # 而且yield會將func生產出來的數據 222 給了 ret。 結果: 111 222
而且個人生成器函數中能夠寫多個yield。
def func(): print("111") yield 222 print("333") yield 444 gener = func() ret = gener.__next__() print(ret) ret2 = gener.__next__() print(ret2) ret3 = gener.__next__() # 最後⼀個yield執⾏完畢. 再次__next__()程序報錯 print(ret3) 結果: 111 222 333 444
當程序運行完最後一個yield,那麼後面繼續運行next()程序會報錯,一個yield對應一個next,next超過yield數量,就會報錯,與迭代器同樣。
yield與return的區別:
return 通常在函數中只設置一個,他的做用是終止函數,而且給函數的執行者一個返回值。
yield 在生成器函數中能夠設置多個,他並不會終止函數,next 會獲取對應 yield 生成的元素。
舉例:
咱們來看一下這個需求:老男孩向樓下賣包子的老闆訂購了10000個包子.包子鋪老闆很是實在,一下就所有都作出來了。
def eat(): lst = [] for i in range(1, 10001): lst.append(f'{i}號包子') return lst e = eat() print(e)
這樣作沒有問題,可是咱們因爲學生沒有那麼多,只吃了2000個左右,剩下的8000個,就只能佔着必定的空間,放在一邊了。若是包子鋪老闆效率夠高,我吃一個包子,你作一個包子,那麼這就不會佔用太多空間存儲了,完美。
def gen_eat(): for i in range(1, 10001): yield f'{i}號包子' e = gen_eat() for i in range(200): print(next(e)) for i in range(300): print(next(e)) # 屢次next包子的號碼是按照順序記錄的。
這二者的區別:
第一種:直接把包子全作出來,佔用內存。
第二種:吃一個,包一個,很是節省內存,並且還能夠保留上次的位置。
yield from
在python3中提供一種能夠直接把可迭代對象中的每個數據做爲生成器的結果進行返回。
# 對比yield 與 yield from def func(): lst = ['衛龍','老冰棍','北冰洋','牛羊配'] yield lst g = func() print(g) print(next(g)) # 只是返回一個列表 def func(): lst = ['衛龍','老冰棍','北冰洋','牛羊配'] yield from lst g = func() print(g) # 他會將這個可迭代對象(列表)的每一個元素當成迭代器的每一個結果進行返回。 print(next(g)) print(next(g)) print(next(g)) print(next(g)) ''' yield from ['衛龍','老冰棍','北冰洋','牛羊配'] 等同於: yield '衛龍' yield '老冰棍' yield '北冰洋' yield '牛羊配' '''
有個小坑,yield from 是將列表中的每個元素返回,因此 若是寫兩個yield from 並不會產生交替的效果。
def func(): lst1 = ['衛龍','老冰棍','北冰洋','牛羊配'] lst2 = ['饅頭','花捲','豆包','大餅'] yield from lst1 yield from lst2 g = func() for i in g: print(i) # 衛龍 # 老冰棍 # 北冰洋 # 牛羊配 # 饅頭 # 花捲 # 豆包 # 大餅
列表推導式
列表推導式分爲兩種模式:
循環模式
將10之內全部整數的平方寫入列表。
ls = [i**2 for i in range(1, 11)] print(ls)
100之內全部的偶數寫入列表。
ls = [i for i in range(2, 101, 2)] print(ls)
從python1期到python100期寫入列表lst。
ls = [f'python{i}期' for i in range(1, 101)] print(ls)
上面那個格式化輸出的變量f'python{i}期',就是加工的變量。
上面作的那三個就是循環模式,比較簡單。
篩選模式
將這個列表中大於3的元素留下來。
l1 = [4, 3, 2, 6, 5, 5, 7, 8] ls = [i for i in l1 if i > 3] print(ls) # [4, 6, 5, 5, 7, 8]
作幾道題:
三十之內能夠被三整除的數。
ls = [i for i in range(1, 31) if i % 3 == 0] print(ls) # [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
過濾掉長度小於3的字符串列表,並將剩下的轉換成大寫字母。
l1 = ['Dylan', 'xiaobai', 'ab', '33434', '1b'] ls = [i.upper() for i in l1 if len(i) > 3] print(ls) # ['DYLAN', 'XIAOBAI', '33434']
找到嵌套列表中名字含有兩個‘e’的全部名字(有難度)
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] ls = [name.upper() for i in names for name in i if name.count('e') == 2] print(ls) # ['JEFFERSON', 'WESLEY', 'STEVEN', 'JENNIFER']
生成器表達式
生成器表達式和列表推導式的語法上如出一轍,只是把[]換成()就好了。好比將十之內全部數的平方放到一個生成器表達式中。
gen = (i**2 for i in range(10)) print(gen) # 結果: <generator object <genexpr> at 0x0000026046CAEBF8>
生成器表達式也能夠進行篩選
# 獲取1-100內能被3整除的數 gen = (i for i in range(1,100) if i % 3 == 0) for num in gen: print(num)
生成器表達式和列表推導式的區別:
列表推導式比較耗內存,全部數據一次性加載到內存。而生成器表達式遵循迭代器協議,逐個產生元素。
獲得的值不同,列表推導式獲得的是一個列表.生成器表達式獲取的是一個生成器。
列表推導式一目瞭然,生成器表達式只是一個內存地址。
不管是生成器表達式,仍是列表推導式,他只是Python給你提供了一個相對簡單的構造方式,由於使用推導式很是簡單,因此大多數都會爲之着迷,這個必定要慎重,推導式只能構建相對複雜的而且有規律的對象,對於沒有什麼規律,並且嵌套層數比較多(for循環超過三層)這樣就不建議你們用推導式構建。
生成器的惰性機制: 生成器只有在訪問的時候才取值,說白了.你找他要纔給你值.不找他要.他是不會執行的.
其它相關推導式(瞭解)
字典推導式
lst1 = ['jay','jj','meet'] lst2 = ['周杰倫','林俊杰','郭寶元'] dic = {lst1[i]:lst2[i] for i in range(len(lst1))} print(dic)
集合推導式
集合推導式能夠幫咱們直接生成一個集合,集合的特色;無序,不重複 因此集合推導式自帶去重功能
s = {abs(i) for i in lst} print(s)
本節咱們講內置函數。 首先來講,函數就是以功能爲導向,一個函數封裝一個功能,那麼Python將一些經常使用的功能(好比len)給咱們封裝成了一個一個的函數,供咱們使用,他們不只效率高(底層都是用C語言寫的),並且是拿來即用,避免重複早輪子,那麼這些函數就稱爲內置函數,到目前爲止python給咱們提供的內置函數一共是68個,因爲時間關係以及考慮這些函數的不一樣重要性咱們會挑經常使用的重要的內置函數去講,就是下面紅色黃色背景的內置函數,剩下的內置函數大家參照着個人博客本身課下練習一下便可。
因爲咱們這沒有表格的功能,我把這些內置函數進行分類:
黃色一帶而過:all() any() bytes() callable() chr() complex() divmod() eval() exec() format() frozenset() globals() hash() help() id() input() int() iter() locals() next() oct() ord() pow() repr() round()
紅色重點講解:abs() enumerate() filter() map() max() min() open() range() print() len() list() dict() str() float() reversed() set() sorted() sum() tuple() type() zip() dir()
藍色將來會講: classmethod() delattr() getattr() hasattr() issubclass() isinstance() object() property() setattr() staticmethod() super()
上面的黃色,紅色的內置函數是在這兩天講完的(講過的就不講了),藍色的講完面向對象會給你們補充,剩餘還有一些課上就不講了,課下練習一下就能夠。
eval:執行字符串類型的代碼,並返回最終結果。
eval('2 + 2') # 4 n=81 eval("n + 4") # 85 eval('print(666)') # 666
exec:執行字符串類型的代碼。
s = ''' for i in [1,2,3]: print(i) ''' exec(s)
hash:獲取一個對象(可哈希對象:int,str,Bool,tuple)的哈希值。
print(hash(12322)) print(hash('123')) print(hash('arg')) print(hash('alex')) print(hash(True)) print(hash(False)) print(hash((1,2,3))) ''' -2996001552409009098 -4637515981888139739 1 2528502973977326415 '''
help:函數用於查看函數或模塊用途的詳細說明。
print(help(list)) print(help(str.split))
callable:函數用於檢查一個對象是不是可調用的。若是返回True,object仍然可能調用失敗;但若是返回False,調用對象ojbect絕對不會成功。
name = 'alex' def func(): pass print(callable(name)) # False print(callable(func)) # True
int:函數用於將一個字符串或數字轉換爲整型。
print(int()) # 0 print(int('12')) # 12 print(int(3.6)) # 3 print(int('0100',base=2)) # 將2進制的 0100 轉化成十進制。結果爲 4
float:函數用於將整數和字符串轉換成浮點數。
complex:函數用於建立一個值爲 real + imag * j 的複數或者轉化一個字符串或數爲複數。若是第一個參數爲字符串,則不須要指定第二個參數。。
print(float(3)) # 3.0 print(complex(1,2)) # (1+2j)
bin:將十進制轉換成二進制並返回。
oct:將十進制轉化成八進制字符串並返回。
hex:將十進制轉化成十六進制字符串並返回。
print(bin(10),type(bin(10))) # 0b1010 <class 'str'> print(oct(10),type(oct(10))) # 0o12 <class 'str'> print(hex(10),type(hex(10))) # 0xa <class 'str'>
divmod:計算除數與被除數的結果,返回一個包含商和餘數的元組(a // b, a % b)。
round:保留浮點數的小數位數,默認保留整數。
pow:求x**y
次冪。(三個參數爲x**y
的結果對z取餘)
print(divmod(7,2)) # (3, 1) print(round(7/3,2)) # 2.33 print(round(7/3)) # 2 print(round(3.32567,3)) # 3.326 print(pow(2,3)) # 兩個參數爲2**3次冪 print(pow(2,3,3)) # 三個參數爲2**3次冪,對3取餘。
bytes:用於不一樣編碼之間的轉化。
# s = '你好' # bs = s.encode('utf-8') # print(bs) # s1 = bs.decode('utf-8') # print(s1) # bs = bytes(s,encoding='utf-8') # print(bs) # b = '你好'.encode('gbk') # b1 = b.decode('gbk') # print(b1.encode('utf-8'))
ord:輸入字符找該字符編碼的位置
chr:輸入位置數字找出其對應的字符
# ord 輸入字符找該字符編碼的位置 # print(ord('a')) # print(ord('中')) # chr 輸入位置數字找出其對應的字符 # print(chr(97)) # print(chr(20013))
repr:返回一個對象的string形式(原形畢露)。
# %r 原封不動的寫出來 # name = 'taibai' # print('我叫%r'%name) # repr 原形畢露 print(repr('{"name":"alex"}')) print('{"name":"alex"}')
all:可迭代對象中,全都是True纔是True
any:可迭代對象中,有一個True 就是True
# all 可迭代對象中,全都是True纔是True # any 可迭代對象中,有一個True 就是True # print(all([1,2,True,0])) # print(any([1,'',0]))