python入門到放棄-函數專題


一、函數的定義

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


#函數的語法: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
    3、在函數中寫 return 值,返回的是一個值
    4、在函數中有返回多個返回值,return 值1、值2、值3... 返回接收到的是元組

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

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

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

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

 

三.函數的參數

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

 

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

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

#相關參數具體位置例子

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

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

 

#實參的相關操作

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

#實參操作的例子:

# 1、位置參數,按照形參的位置,給形參傳值
#例子
# 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):

#形參操作的例子:

#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 關鍵字動態傳參
#   以上參數可以任意搭配使用,但是要注意順序問題,要不然會有問題
形參相關操作例子

 

#參數的位置順序排列

位置參數->位置參數動態傳參*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__) #查看字符串的文檔注釋

 

#關於參數的聚合和打散

#形參:聚合
# 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)  #打散成關鍵字參數
打散和聚合例子

 

五.函數名

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

#函數名的相關操作

1.函數名可以賦值給其他變量
2.函數名可以作為參數列表中的元素進行存儲,作容器類的元素
3.函數名可以作為參數傳遞給函數
4.函數名可以作為函數的返回值

#函數名相關操作例子:

# 1、函數名的內存地址
# 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.可以讓一個變量常駐內存

#例子:

#作用例子:
#1、保護變量不受侵害
#首先舉一個全局變量不安全的例子
# 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

#2、讓一個變量常駐內存
# 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.得到的值不一樣,列表推導式得到的是一個列表,生成器表達式獲取的是生成器


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM