python入門到放棄-函數專題

1、函數的定義

函數是對代碼塊和功能的封裝和定義


#函數的語法:def是define的意思,定義
最基本的語法:
    def 函數名():
        函數體
   函數名() #調用函數
帶有參數的語法
def 函數名(形參列表): 函數體(代碼塊,return) 函數名(實參列表) :調用

#例子:函數執行過程
# def wan():  #定義函數
#     print("今天一塊兒去玩")
#     print("去哪裏玩呢")
#     print("我不知道")
# wan()  #調用函數
'''講解執行的過程
    1.定義函數wan()
    2.調用函數wan()
    3.準備開始執行函數
    4.打印,今天一塊兒去玩
    5.打印,去哪裏完
    6.打印,我不知道
    7.函數執行完畢,本次調用完畢,wan()函數調用完畢
'''

 

二.return返回值的相關操做

return:在函數執行的時候,若是遇到return,則直接返回,和while循環中break同樣
    1、若是函數什麼都不寫,不寫return,沒有返回值,獲得的是Nano
    2、在函數中間或者末尾寫return,返回的是None
    三、在函數中寫 return 值,返回的是一個值
    四、在函數中有返回多個返回值,return 值一、值二、值3... 返回接收到的是元組

#例子:    
#一、函數什麼都不寫,不寫return,返回的是None
def wan():
    print("今天一塊兒去玩")
    print("去哪裏玩呢")
    print("我不知道")
ret = wan()
print(ret)  #None

#二、在函數中間或者末尾寫return,返回的是None
def wan():
    print("今天一塊兒去玩")
    return
    print("去哪裏玩呢")
    print("我不知道")
ret = wan()
print(ret)  #在執行完第一個print的時候就返回None,就結束了

#三、在函數中寫一個return 值,返回的是一個值
def wan():
    print("今天一塊兒去玩")
    return "鍋蓋"
    print("去哪裏玩呢")
    print("我不知道")
ret = wan()
print(ret)
#今天一塊兒去玩
#鍋蓋
#會看到返回鍋蓋就結束了

#四、函數中有返回多個返回值,那麼返回的是一個元組
def wan():
    print("今天一塊兒去玩")
    return "鍋蓋","番薯","大塊"
    print("去哪裏玩呢")
    print("我不知道")
ret = wan()
print(ret)  ##('鍋蓋', '番薯', '大塊')
相關操做

 

三.函數的參數

函數在調用的時候指定具體的一個變量的值,就是參數

 

#參數包括:形參,實參,傳參python

形參:函數聲明的位置的變量
實參:函數調用的時候給的具體的值
傳參:把實參交給形參的過程

#相關參數具體位置例子面試

#形參和實參的位置
# def wan(形參):  #在函數聲明的位置的變量就是形參
#     print(好玩)
# 
# wan(實參) :#在函數調用的地方給的具體的值就是實參

#例子
# def wan(what):
#     print("手機")
#     print("去哪裏"+what)
# wan("廣西")
#在調用wan的時候給what一個值,而後執行函數體

 

#實參的相關操做算法

#包括
    1.位置參數:按照形參的參數位置,給形參傳值
    2.關鍵字參數:按照形參的名字給形參傳值
    3.混合參數:即用位置參數,也用關鍵字參數

#實參操做的例子:安全

# 一、位置參數,按照形參的位置,給形參傳值
#例子
# def chi(moning,after,night):
#     print(moning,after,night)
# chi("玉米餃","米飯","麪條") #玉米餃 米飯 麪條


#2.關鍵字參數: 按照形參的名字給形參傳值
# def chi(moning,after,night):
# #     print(moning,after,night)
# # chi(after="米飯",moning="餃子",night="麪條") #餃子 米飯 麪條

# 3.混合參數:即用位置參數,也用關鍵字參數
# def chi(moning,after,night):
#     print(moning,after,night)
# chi("餃子","米飯",night="麪條") #餃子 米飯 麪條

#注意:
    #順序位置:要先寫位置後再寫關鍵字,要否則會報錯
#例子
# chi("餃子",night="麪條","米飯")  #會報紅色
#SyntaxError: positional argument follows keyword argument
#語法錯誤:關鍵字參數後面跟了位置參數

 

#形參的相關操做閉包

#包括
    1.位置參數
    2.默認值參數,要先寫位置參數以後才能寫默認值參數
    3.動態參數
     包括:位置參數動態傳參 *args,關鍵字參數動態傳參**kwargs
    無敵傳參方法:def func(*args,**kwargs):

#形參操做的例子:app

#1.位置參數,按照位置來進行賦值
# def chi(moning,after,night):
#     print(moning)
#     print(after)
#     print(night)
# chi("餃子","米飯","麪條")


#2.默認值參數
#例子:好比一個班上要錄入學生信息,有大部分都是男生,就能夠設置一個默認值是男
# def stu_inf(name,age,sex='男'):
#     print("錄入學生信息")
#     print(name,age,sex)
#     print("錄入完畢")
# stu_inf("蔣小魚",18)
# stu_inf("張衝",22)
# stu_inf("沈擱",22,sex="女") #若是不想使用默認值也能夠本身設定

#注意點:
    #必須先聲明位置參數,才能聲明默認值參數,不然會有問題
#例子
# def stu_inf(name,sex='男',age): #很明顯這種寫法是錯誤的


#3.位置參數的動態傳參
#     * 在這裏表示接收位置參數的動態傳參,接收到的是元組
# def chi(*foot):  #參數名是food, * 表示動態傳參
#     print(foot)
# chi("米飯","麪條","餃子")  #('米飯', '麪條', '餃子')
# chi("饅頭")
# chi()

# def chi(name,*food,location="河北"):
#     print(location)
#     print(name+"要吃",food)
# chi("張三","餃子","麪條")

#要注意參數的書寫順序
#順序: 位置參數 -> 位置參數動態傳參 -> 默認值參數
#錯誤寫法
# def chi(name,location="河北",*food):
#     print(location)
#     print(name+"要吃",food)
# chi("張三","餃子","麪條")   #這樣寫的話餃子就成了默認值
# 餃子
# 張三要吃 ('麪條',)
'''


#關鍵字的動態傳參
'''
# def chi(**food):
#     print(food)
#
# chi(good_food="大米",no_good_food="麪條",dirnk="水")
#前面得是變量,若是寫數字或者字符串這種就會報錯,如:"大海" = "蝦"

# def chi(*food2,**food):
#這樣是無敵傳參
#     print(food)
#
# chi(good_food="大米",no_good_food="麪條",dirnk="水")

#提示:
#   位置參數,*args(位置關鍵字動態傳參) 默認值參數 **kwargs 關鍵字動態傳參
#   以上參數能夠任意搭配使用,可是要注意順序問題,要否則會有問題
形參相關操做例子

 

#參數的位置順序排列ide

位置參數->位置參數動態傳參*args->默認值參數->關鍵字參數動態傳參**kwargs

四.函數的註釋

在函數裏面用三個單引號或三個雙引號引發來的就是函數的註釋

#例子:寫好註釋讓別人能看明白,能省去不少事情函數

# def chi(food,drink):
#     """
#     這裏是函數的註釋,先寫一下當前這個函數是幹什麼的,不如我這個函數就是一個吃
#     :param food: 參數food是什麼意思
#     :param drink:  參數drink是什麼意思
#     :return:   返回的是什麼東西
#     """
#     print(food,drink)
#     return "good"
# print(chi.__doc__)   #document 文檔
# print(str.__doc__) #查看字符串的文檔註釋

 

#關於參數的聚合和打散spa

#形參:聚合
# def func(*food):
#     print(food)
# lst = ["大麻花","餃子","麪條","土豆"]
# func(lst) #這樣調用的話是一個列表在裏面的

# # 實參: 打散
# func(lst[0],lst[1],lst[2],lst[3]) #將上面的大三, 把list,tuple,set,str進行迭代打散
# func(*lst)  #上面的打散寫不方便,寫*號更方便簡單
# #可是上面的打散都是一個一個的,那麼字典呢?

#字典的打散方式
#聚合成關鍵字參數
# def func(**kwargs):
#     print(kwargs)
# dic = {"name":"sir","age":"18"}
# func(**dic)  #打散成關鍵字參數
打散和聚合例子

 

五.函數名

函數名也是一個變量,可是一個特殊的變量,與括號配合能夠執行函數的變量

#函數名的相關操做3d

1.函數名能夠賦值給其餘變量
2.函數名能夠做爲參數列表中的元素進行存儲,做容器類的元素
3.函數名能夠做爲參數傳遞給函數
4.函數名能夠做爲函數的返回值

#函數名相關操做例子:

# 一、函數名的內存地址
# def func():
#     print("哈哈")
# print(func)  #由於尚未進行調用
#結果:<function func at 0x0000025A9344C1E0>


# 2.函數名能夠賦值給其餘變量
# def func():
#     print("哈哈")
#
# print(func)
# a = func #把函數當成一個變量賦值給另外一個變量
# a()  #函數調用func()
#打印哈哈


# 3.函數名能夠看成容器類的元素
# def func1():
#     print("哈哈")
#
# def func2():
#     print("哈哈")
#
# def func3():
#     print("哈哈")
#
# lst = [func1,func2,func3]
# for i in lst:
#     i()


# 4.函數名能夠做爲參數傳遞給函數
# def my():
#     print("我是my")
#
# def proxy(fn):
#     fn() #執行傳遞過來的my
# proxy(my)
#過程:首先調用proxy函數,將my參數傳遞給proxy,而後變成proxy(my),而後調用my()
    #接着打印"我是my"

#函數名能夠做爲參數進行傳遞(多層嵌套)
# def func():
#     print("我是func")
# def func1():
#     print("我是func1")
#
# def func2(fn):
#     print("我是func2")
#     fn()
# func2(func1)  #結果:我是func2,我是func1
#解釋:首先執行func2函數,而後有個實參傳遞給形參,打印我是func2,而後執行func1()函數打印我是func1

#例二:
# def func():
#     print("我是func")
# def func1():
#     print("我是func1")
#
# def func2(fn,gn):
#     print("我是func2")
#     fn()
#     gn()
#     print("hahaha")
# func2(func1,func)
# 我是func2
# 我是func1
# 我是func
# hahaha
#解釋:首先執行func2函數,有兩個實參傳遞給形參,打印我是func2,接着執行func1函數打印我是func1,
    #接着執行funch函數打印我是func,在打印hahaha


# 5.函數名能夠做爲函數的返回值
# def func():
#     print("我是func")
#     a = 10 # 變量
#     def inner():
#         print("我是inner")
#     return inner  #得出inner,而後使用inner()調用
# print(func)
# ret = func()
# ret()
# func()() #先運行func() 而後再返回值上加()
操做例子

 

六.函數的嵌套

1.主要碰見()就是函數被調用了,若是沒有()就不是函數的調用
2.函數的執行順序

#函數嵌套例子

#例子:
# def fun():
#     print(111)
# def fun1():
#     print(222)
#     fun()
# fun1()
# print(111)
#結果是222,111,111
#解釋:定義函數,而後最早調用的是fun1這個函數,因此先的打印fun1中的內容,
    #接着再調用fun()函數,再打印111,接着再打印111

#例二
# def fun1():
#     print("蔣小雨")
#     def fun2():
#         print("魯炎")
#     def fun3():
#         print("張衝")
#         def fun4():
#             print("龍大隊")
#             fun2()
#         fun4()
#     fun3()
# def fun5():
#     print("二哈")
#     fun1()
# fun5()
#二哈,蔣小雨,張衝,龍大隊,魯炎
#分析:首先調用fun5,打印二哈,接着調用fun1,打印蔣小雨,而後調用fun3的函數,打印張衝
    #接着執行下面函數體代碼塊,調用fun4,打印龍大隊,接着調用fun2打印魯炎
嵌套例子

 

七.命名空間

把存放名字和值的關係的空間叫作命名空間

#命名空間分類

1.全局命名空間:在py文件中,函數外聲明的變量都屬於全局命名空間
2.局部命名空間:在函數中聲明的變量會放在局部命名空i教案
3.內置命名空間:存放python解釋器爲咱們提供的名字
           如:list,tuple,str,int這些就是內置命名空間

#取值順序

1.局部命名空間
2.全局命名空間
3.內置命名空間

#取值順序例子:
a = 10 #全局命名空間
def func():
    a = 20 #局部命名空間
    print(a)
func() #20 

 

八.做用域

定義:做用域就是做用的範圍,按照生效範圍分爲:全局做用域和局部做用域

全局做用域:包含內置命名空間和全局命名空間,在整個文件均可以使用
      能夠經過globals()函數來查看全局做用域中的內容
局部做用域:在函數內部可使用
      能夠經過locals()函數來查看局部做用域中的變量和函數信息

#例子:

#例子
# a = 10
# def func():
#     a = 40
#     b = 20
#     def abc():
#         print("哈哈")
#     print(a,b)  #這裏使用的是局部做用域
#     print(globals()) #打印全局做用域中的內容
#     print(locals())  #打印局部做用域中的內容
# func()

 

#關鍵字global和nonlocal講解

global:更改全局變量中的值
    理解:在局部中定義一個局部變量,而後加了global,就會將全局中定義的變量的值改爲局部的那個變量的值

#global的應用
#例子
# a = 10
# def func():
#     global a
#     a += 10
#     print(a)
# func() #20 ,加了global就能夠改變外部的值了,若是不加是不能更改的

#例如:不加global更改全局參數的時候就會報錯
# a = 10
# def func1():
#     a += 10
#     print(a)
# func1()
#總結點:全局變量自己就是不安全的,不能隨意修改


nonlocal:尋找外層函數中離他最近的那個變量
#例子:
# a = 10
# def func1():
#     a = 20
#     def func2():
#         nonlocal a
#         a = 30
#         print(a)
#     func2()
#     print(a)
# func1()
# print(a) #30,30,10
#nonlocal是更改離他最近的那個變量,因此,將上一個a=20,改成30
#因此打印是30,30,10,由於nonlocal將20改爲了30
詳解

 

九.閉包

定義:在內層函數中訪問外層函數的變量

閉包的做用:
    1.能夠保護變量不受侵害
    2.可讓一個變量常駐內存

#例子:

#做用例子:
#一、保護變量不受侵害
#首先舉一個全局變量不安全的例子
# a = 10
# def outer():
#     global a
#     a = 20
#     print(a)
#
# def outer_2():
#     global a
#     a = 30
#     print(a)
#
#
# outer()
# outer_2()
#得出結果是20,30
#解釋:首先調用outer()函數更改成20,而後再調用outer_2函數打印30
#       這樣就會出現哪一個先調用就執行那個,因此改來改去是很混亂的

# def outer():
#     a = 10  #這個變量對外界是不開放的
#     def func():
#         nonlocal a  #尋找外層函數中離他最近的那個進行修改
#         a = 20
#         print(a)
#     func()
# outer()
# 
# def outer_2(): #這個函數不能對a = 10進行修改
#     pass

#二、讓一個變量常駐內存
# def outer():
#     a = 10  #常駐內存,爲了inner執行的時候有值,由於你不知何時調用
#     def inner():
#         print(a)
#     return inner
# fn = outer()
# print("大大大")
# print("笑笑笑")
#
# fn() #至關於inner(),調用inner函數


#使用 _closure_ 查看函數是否是閉包

#例子:不是閉包的檢測
# def outer():
#     def func():
#         print("我不是閉包")
#     print(func.__closure__)  #None
# outer()

#例二:是閉包
# def outer():
#     a = 10
#     def func():
#         print(a)
#     print(func.__closure__)
# outer()  #(<cell at 0x000001B7B3E7D978: int object at 0x00007FF97124B470>,)

#結論:若是打印的是None,不是閉包,若是不是None,就是閉包
做用例子

 

十.迭代器

#迭代器
#   能夠簡單理解爲:通用的去遍歷某個對象的方式

#有些數據類型是可迭代的,有些是不可迭代的,若是使用不可迭代的來進行循環就會報錯

#例子:使用不可迭代對象來進行循環就會報錯
# s = 123
# for i in s:
#     print(i)
#這樣打印會報錯: TypeError: 'int' object is not iterable:數字不是一個可迭代對象

#那麼問題就來了,怎麼知道是否是一個可迭代對象呢?
#能夠經過dir查看xx類型的數據能夠執行哪些方法
# print(dir(str))  #__iter__ iterable(可迭代)
# print(dir(list)) #__iter__
# print(dir(int))    #若是沒有__iter__,說明不是可迭代對象,不是可迭代對象那麼相對應的就不能進行循環

#結論:全部的帶__iter__是可使用for循環的,是可迭代對象

#可迭代對象就可使用__iter__()來獲取到迭代器
#迭代器裏面有__next__()
# s = "我喜歡看火藍刀鋒"
# it = s.__iter__() #獲取迭代器
# print(dir(it))   #迭代器裏有__iter__ 還有__next__

#迭代器的特色

1.只能向前取,下一個下一個,不能往回
2.幾乎不佔用內存,能夠有效節省內存
3.for循環
4.惰性機制

#例子:
1.只能向前拿
#print(it.__next__()) #我
# print(it.__next__()) #喜
# print(it.__next__()) #歡
# print(it.__next__()) #看
# print(it.__next__()) #火

2.迭代器模擬for循環
# lst = ["蔣小雨","張衝","魯炎","龍大隊"]
# for el in lst: #底層使用的是迭代器
#     print(el)
特色

#判斷數據是否可迭代

#例子:
# lst = ["張衝","魯炎","蔣小雨"]

#it = lst.__iter__()

# print("__iter__" in dir(it))  #True
# print("__next__" in dir(it))  #True
# print(list(it))
#經過dir來判斷數據是否可迭代的,以及數據是不是迭代器
#
# #官方方案
# from collections.abc import Iterable #可迭代對象
# from collections.abc import Iterator  #迭代器
#
# print(isinstance(lst,Iterable))  #True
# print(isinstance(lst,Iterator))  #False lst列表自己不是迭代器

 

十一.生成器

1.生成器的本質就是迭代器,和迭代器的特色同樣,取值方式和迭代器同樣(__next__(),send()
2.在python種有三種方式來獲生成器
    1.經過生成器函數
    2.經過各類推導式來實現生成器
    3.經過數據的轉換也能夠獲取生成器

 

生成器函數

1.函數中若是由yield函數就是生成器函數
2.生成器函數在執行的時候,默認不會執行函數體,會返回生成器
3.yield:至關於return能夠返回數據,可是yield不會完全中斷函數,會分段執行函數

#例子:不執行函數體,拿到的是生成器
# def func():
#     print('哈哈')
#     yield 1
#     print('呵呵呵')
# gen = func() #這樣子你就會發現不會執行你的函數,拿到的是生成器,若是是return的話就會執行函數了
# print(gen.__next__()) #這樣子就會執行函數,執行到下一個yield,就是說執行看到yield就結束

#生成器應用

#應用場景
# 好比你喜歡吃雞蛋,設想你去市場能夠一會兒就買一萬個,這樣也是能夠,可是有個問題就是雞蛋久了就會爛,存放是個問題,這樣就會很浪費,可是若是你買了個雞回來,就能夠解決掉存放空間問題,想何時吃就拿一個

#例子:一會兒買一萬個浪費
# def egg():
#     lst = []
#     for i in range(10000):
#         lst.append('雞蛋'+str(i))
#         return lst
# ll = egg() #一會兒買10000個就會很佔用內存

#例二:買只雞,生雞蛋,想吃一個就拿一個
# def egg():
#     for i in range(10000):
#         yield '雞蛋'+str(i)
# g = egg() #獲取生成器
# sir = g.__next__()
# print(sir) #雞蛋0
# sir1 = g.__next__()
# print(sir1) #雞蛋1
#這樣子就是想吃一個就拿一個

#這樣子也驗證了生成器的3個特色
#   1.惰性機制,拿一個纔給你取一個
#   2.省內存
#   3.只能向前拿
應用場景

 

#send()方法

send()和__next__()是同樣的,能夠執行到下一個yield,能夠給上一個yield位置傳值

#send和__next__()區別:
    1.send和next()都是讓生成器走下一次
    2.send能夠給上一個yield的位置傳遞值,不能給最後一個yield發送值,在第一次執行生成器代碼的時候不能使用send()

#使用send給上一個yield傳值例子:

#例子:使用send給上一個yield傳值
def func():
    print("我吃什麼啊")
    a = yield "玉米"  #這裏的a和後面的yield是沒關聯的,會把傳進來的值交給print執行
    print("a=",a)
    b = yield "餃子"
    print("b=",b)
    c = yield "包子"
    print("c=",c)
    yield "OVER"  #最後收尾的必定是yield,否則會有報錯

g = func() #獲取生成器,記住有yield的是生成器函數,只會給你獲取到生成器,不會執行函數體
ret1 = g.__next__() #沒有上一個yield,因此不能使用send(),開頭必須__next__()
print(ret1)
ret2 = g.send("大餅")
print(ret2) #a=大餅
ret3 = g.send("")
print(ret3) #b=粥
ret4 = g.send("冰淇淋")
print(ret4) #c=冰淇淋
#解析:執行時候首先我吃什麼啊,而後打印玉米,接着ret2使用send上一個yield傳值,因此就變成a=大餅,接着打印a=大餅
#       要注意變量和右邊的yield是兩段來的,互不相干,接着打印餃子,ret3使用send給上一個yield傳值,變成b=粥,接着繼續執行
傳值例子

 

#生成器可使用for循環來獲取內部的元素

#爲何生成器可使用for循環呢,由於生成器實質就是迭代器
#例子:
def func():
    print(111)
    yield 222
    print(333)
    yield4444
    print(555)
    yield 666
for i in func():
    print(i)

 

十二.推導式

1.推導式:就是使用一句話來生成
2.包括:列表推導式,字典推導式,集合推導式,
3.注意點:沒有元組推導式
4.3種推導式的語法:
    1.列表推導式:[結果 for循環 條件判斷]
    2.字典推導式:{k:v for循環 條件判斷}
    3.集合推導式:{k for循環 條件判斷}

#3種推導式的應用

#1.列表推導式
        語法: [結果 for循環 判斷語句]

#例子:首先咱們先來一個打印一年級到12年級,咱們可能想到的是定義一個空列表,而後把元素追加到列表裏面
# lst = []
# for i in range(1,13):
#     lst.append("年級"+str(i))
# print(lst)

#若是使用推導式的話,那麼就是使用一句話來生成一個列表
# lst = ["年級"+str(i) for i in range(1,13)]
# print(lst)  #和上面列表追加同樣的效果

#例二:使用推導式取1-100的奇數
# lst = [i for i in range(100) if i%2 == 1]
# print(lst)

#例三:尋找名字中帶有兩個e的人的名字
# names = [['Tom','tomi','findall','Wesley','Steven','Jon'],['Alice','Ana','Jennifer','Eva']]
#邏輯:首先打開第一層列表,拿到下列表,而後再到小列表裏面拿元素,再進行統計判斷

#使用推導式寫
# lst = [name for line in names for name in line if name.count('e') ==2]
# print(lst) #['Wesley', 'Steven', 'Jennifer']

#使用常規算法寫
# lst = []
# for line in names:
#     for name in line:
#         if name.count('e') == 2:
#             lst.append(name)
# print(lst) #['Wesley', 'Steven', 'Jennifer']


#2.字典推導式
        語法:{key:value for循環 條件判斷}

#例子:將列表的元素轉換成字典,轉換形式:[11,22,33,44] => {0:11,1:22,2:33}
# lst = [11,22,33,44]
# dic = {i:lst[i] for i in range(len(lst))}
# print(dic) #{0: 11, 1: 22, 2: 33, 3: 44}

#例二:將字典的key和value進行調換
#   思路:首先先拿到key和value,而後在推導式的結果那裏掉不一樣位置就能夠了
# dic = {"zs":"趙四","ln":"劉能","zc":"張衝","ly":"魯炎"}
# d = {v:k for k,v in dic.items()}
# print(d) #{'趙四': 'zs', '劉能': 'ln', '張衝': 'zc', '魯炎': 'ly'}


#3.集合推導式
#要記住集合的特色:去重,無序,元素必須式可哈希不可變的數據類型
#例1:使用集合推導式去重複
# s = {i for i in range(100)}
# print(s)

#例二:去重複
# lst= [1,2,3,4,2,1,3,4,6,7]
# s = {el for el in lst}
# print(s) #{1, 2, 3, 4, 6, 7}
推導式應用

 

十三.生成器表達式

1.生成器表達式能夠直接獲取到生成器對象,生成器對象能夠直接進行for循環,生成器具備惰性機制
2.生成器表達式語法:
        (結果 for 變量 in 可迭代對象 if 條件判斷)

#生成器表達式應用

#下面將演示生成器的最大點特,惰性機制,要拿纔給你拿一個,拿走了就沒有值了
# def func():
#     print(111)
#     yield 222
#     yield 333
#
# a = func() #獲取到生成器
# a1 = (i for i in a)  #生成器
# a2 = (i for i in a1) #生成器
# print(list(a)) #[222, 333]
# print(list(a1)) #[]
# print(list(a2)) #[]
#分析:爲何前面的a有值,後面的都沒有值了?
#解:由於a是源頭,他從源頭把數據給拿走了,因此後面再從前面拿的話就不會有值了,這就驗證了生成器的惰性機制,你拿一個纔給你一個,拿走了就沒有了

#那麼後面還能不能獲取到值? 答案是能夠的,能夠再作一個源頭,再拿數據
#例如:再定義一個a3獲取生成器,再進行調用,這樣子a2就有值了
# def func():
#     print(111)
#     yield 222
#     yield 333
#
# a = func() #獲取到生成器
# a1 = (i for i in a)  #生成器
# a3 = func()
# a2 = (i for i in a3) #生成器
# print(list(a)) #[222, 333]
# print(list(a1)) #[]
# print(list(a2)) #[222, 333] #
應用

#面試題

#題目:計算拿到的值是多少
#求和函數
# def add(a,b):
#     return  a + b

#生成器函數
# def test():
#     for r_i in range(0,4):
#         yield r_i
#
# g = test() #獲取到生成器
#
# for n in [2,10]:
#     g = (add(n,i) for i in g)

#上的for能夠當作循環量詞
# for n in [2]:
#     g = (add(n,i) for i in g)
# for n in [10]:
#     g = (add(n,i) for i in g)
#由於是2還沒取值,因此是疊加進去,將g換成上面
#  g = (add(n,i) for i in (add(n,i) for i in 0,1,2,3)

# print(list(g)) #20,21,22,23
#分析:第一個函數是來求和得,第二個函數是生成器函數,沒有打印值,而後到for循環,能夠想象是2和10都執行了一次,可是由於生成器得惰性機制,而後執行2是沒有值,因此是不關2的事情,執行10得時候纔會執行,將10帶進去算
#最後的執行是這樣:g = (add(10,i) for i in (add(10,i) for i in 0,1,2,3),因此就成10+10,10+11,10+12,10+13

#提示:惰性機制,不到最後是不會拿值得


#下面接着演示列表有多個值,可是它只會看最後面的那個,前面的會相加
# def add(a,b):
#     return  a + b

#生成器函數
# def test():
#     for r_i in range(0,4):
#         yield r_i
# g = test() #獲取到生成器
# 
# for n in [1,3,7]:
#     g = (add(n,i) for i in g)
#這個就是至關於疊加了3次
# g = (add(7,i) for i in (add(7,i) for i in (add(7,i) for i in 0,1,2,3)

# print(list(g))  #21,22,23,24
#最後的運算是:(add(7,i) for i in (add(7,i) for i in (add(7,i) for i in 0,1,2,3) #將7帶進去運算,把最後那個帶進去算
#首先是0+7,1+7,2+7,3+7,接着7+7,7+8,7+9,7+10,而後7+14,7+15,7+16,7+17
面試題及講解

 

#生成器表達和列表推導式的區別

1.生成器表達式比較省內存,列表推導式比較耗內存
2.獲得的值不同,列表推導式獲得的是一個列表,生成器表達式獲取的是生成器
相關文章
相關標籤/搜索