函數部分總結
一、自定義函數
一、函數概念
1、什麽是函數:函數就是封裝一個功能。(程序中如果沒有函數的引用,會產生重復代碼多,可讀性差的特點。)
2、函數的定義:def 關鍵詞開頭,空格之後接函數名稱和圓括號()
l1 = [1,2,3,4] def my_len(): # def 關鍵字 定義一個函數 # my_len 函數名書寫規則與變量一樣 # def與函數名中間一個空格 # 函數名():加上冒號 # 函數體 count = 0 for j in l1: count += 1 print(count) my_len()
l1 = [1,2,3,4] def my_len(): count = 0 for j in l1: count += 1 return count print(my_len()) # 函數的返回值: # 寫函數,不要在函數中寫print() # return # 1、在函數中,遇到return結束函數。 # 2、將返回值給函數的調用者。 # 無 return = return None # return 1個值 該值是什麽,就直接返回給函數的調用者,函數名() # return 多個值,將多個值放到一個元組中,返回給函數的調用者。
二、函數的傳參
函數分為形參和實參:
形參:形式參數,不代表實際的變量。
實參:實際參數,帶入形參中的變量。
形參傳參:1、位置傳參。按順序,一一對應。
2、默認參數。傳參則覆蓋,不傳則默認,默認參數永遠在位置參數的後面。
形參傳參:1、位置傳參。按順序,一一對應。
2、關鍵字傳參,不按順序,一一對應。
3、混合傳參,關鍵字參數永遠在位置參數的後面。
形參傳遞順序:位置參數,*args,默認參數,**kwargs
def test(a, *args, **kwargs): print(a) # 1 print(args) # (2, 3) print(kwargs) # {‘e‘: 5, ‘d‘: ‘4‘} test(1, 2, 3, d=‘4‘, e=5) # 1還是參數a的值,args表示剩余的值,kwargs在args之後表示成對鍵值對。
# * 魔法運用 def func(*args): print(args) l1 = [1,2,30] l2 = [1,2,33,21,45,66] tu = (1,2,3) func(1,2,30,1,2,33,21,45,66) # (1, 2, 30, 1, 2, 33, 21, 45, 66) func(*‘qweqrfdsaf‘) # (‘q‘, ‘w‘, ‘e‘, ‘q‘, ‘r‘, ‘f‘, ‘d‘, ‘s‘, ‘a‘, ‘f‘) func(*{‘name‘:‘alex‘,"age":12}) # (‘name‘, ‘age‘) func(*l1,*l2) # (1, 2, 30, 1, 2, 33, 21, 45, 66) def func(*args): print(args) func(1,2,3,10,20,80) # (1, 2, 3, 10, 20, 80) def func(**kwargs): print(kwargs) dic1 = {‘name1‘:‘alex‘,‘age1‘:46} dic2 = {‘name‘:‘老男孩‘,‘age‘:56} func(**dic1,**dic2) # {‘age1‘: 46, ‘name1‘: ‘alex‘, ‘name‘: ‘老男孩‘, ‘age‘: 56} # 在函數的調用執行時, # *可叠代對象,代表打散(list,tuple,str,dict(鍵))將元素一一添加到args。 # **字典,代表打散,將所有鍵值對放到一個kwargs字典裏。 # 在函數定義時, *args,**kwargs代表的是聚合。 def func(*args,**kwargs): print(args) print(kwargs) dic1 = {‘name1‘:‘alex‘,‘age1‘:46} dic2 = {‘name‘:‘老男孩‘,‘age‘:56} func(*[1,2,3,4],*‘asdfsad‘,**dic1,**dic2) # (1, 2, 3, 4, ‘a‘, ‘s‘, ‘d‘, ‘f‘, ‘s‘, ‘a‘, ‘d‘) # {‘name‘: ‘老男孩‘, ‘name1‘: ‘alex‘, ‘age‘: 56, ‘age1‘: 46}
三、函數有用信息
def func1(): """ 此函數是完成登陸的功能,參數分別是...作用。 :return: 返回值是登陸成功與否(True,False) """ print(666) return True func1() # 666 print(func1.__name__) # func1 print(func1.__doc__) # 顯示註釋內容
二、命名空間和作用域
一、命名空間
命名空間的本質:存放名字與值的綁定關系
命名空間一共分為三種:
全局命名空間:代碼在運行伊始,創建的存儲“變量名與值的關系”的空間
局部命名空間:在函數的運行中開辟的臨時的空間
內置命名空間:存放了python解釋器
三種命名空間之間的加載與取值順序:
加載順序:內置命名空間(程序運行前加載)->全局命名空間(程序運行中:從上到下加載)->局部命名空間(程序運行中:調用時才加載)
取值:在局部調用:局部命名空間->全局命名空間->內置命名空間
在全局調用:全局命名空間->內置命名空間
二、作用域
作用域就是作用範圍,按照生效範圍可以分為全局作用域和局部作用域。
全局作用域(globals):包含內置名稱空間、全局名稱空間,在整個文件的任意位置都能被引用、全局有效
局部作用域(locals):局部名稱空間,只能在局部範圍內生效
global關鍵字
#global # 1,在局部空間內,聲明一個全局變量 def func1(): global name name = ‘老男孩‘ print(name) # 老男孩 func1() print(name) # 老男孩 # 2,在局部空間內改變一個全局變量 a = 4 def func1(): global a # 5 a = 5 func1() print(a)
nolocal關鍵字
#nonlocal # 1,不能修改全局變量。 #在局部作用域中,對父級作用域(或者更外層作用域非全局作用域)的變量進行引用和修改, # 並且引用的哪層,從那層及以下此變量全部發生改變。 a = 4 def func1(): b = 6 def func2(): b = 666 print(b) # 666 func2() print(b) # 6 func1() b = 4 def func1(): b = 6 def func2(): nonlocal b b = 666 print(b) # 666 func2() print(b) # 666 print(b) # 4 func1()
三、函數名的應用
# 函數名是函數的名字,本質:變量,特殊的變量。 # 1,單獨打印函數名 <function func1 at 0x0000000000872378> def func1(): print(666) print(func1) # <function func1 at 0x0000000000872378> a = 6 print(a) # 6 # 2、函數名的賦值 def func2(): print(666) f = func2 f() # 666 # 3、函數名可以作為容器類數據的元素 def f1(): print(1211) def f2(): print(1222) def f3(): print(1233) def f4(): print(1233) l1 = [f1, f2, f3, f4] for i in l1: i() # 4、函數名可以作為參數 a = 1 def f1(x): print(x) # 1 f1(a) def f1(): print(666) def f2(x): # x = f1 x() # f1() f2(f1) # 5、函數名可以作為函數的返回值 def wraaper(): def inner(): print(666) return inner ret = wraaper() # inner ret() # inner()
三、閉包和裝飾器
一、閉包
閉包:就是內層函數對外層函數(非全局)變量的引用。
閉包:當函數開始執行時,如果遇到閉包,他又一個機制,他會永遠開辟一個內存空間,將閉包中的額變量等值放入其中,不會隨著函數的執行完畢而消失。
判斷是不是閉包:內層函數名.__closure__ 結果是:cell...就是閉包
name = ‘老男孩‘ def wraaper2(n): # n = ‘老男孩‘ def inner(): print(n) # 老男孩 inner() print(inner.__closure__) # (<cell at 0x000001E3F9123B28: str object at 0x000001E3F9010F30>,) wraaper2(name)
二、裝飾器
開放封閉原則:
1、對擴展是開放的
2、對修改是封閉的
裝飾器主要功能和裝飾器固定結構:在不改變函數調用方式的基礎上在函數的前、後添加功能。
裝飾器固定格式
def timer(func): def inner(*args,**kwargs): ‘‘‘執行函數之前要做的‘‘‘ re = func(*args,**kwargs) ‘‘‘執行函數之後要做的‘‘‘ return re return inner
帶參數的裝飾器
def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print(‘‘‘執行函數之前要做的‘‘‘) re = func(*args,**kwargs) if flag: print(‘‘‘執行函數之後要做的‘‘‘) return re return inner return timer @outer(False) def func(): print(111) func()
多個裝飾器裝飾同一個函數
def wrapper1(func): def inner(): print(‘wrapper1 ,before func‘) # 第二步 func() print(‘wrapper1 ,after func‘) # 第四步 return inner def wrapper2(func): def inner(): print(‘wrapper2 ,before func‘) # 第一步 func() print(‘wrapper2 ,after func‘) # 第五步 return inner @wrapper2 @wrapper1 def f(): print(‘in f‘) # 第三步 f()
四、叠代器和生成器
一、叠代器
可叠代協議:可以被叠代要滿足的要求,可以將某個數據集內的數據“一個挨著一個的取出來”,就叫做叠代,內部實現了__iter__方法
叠代協議:必須擁有__iter__方法和__next__方法
叠代器的好處:
1、節省內存空間。
2、滿足惰性機制。
3、不能反復取值,不可逆。
可叠代計算過程:
1、將可叠代對象轉化成叠代器
2、內部使用__next__方法取值
3、運用了異常處理去處理報錯。
l2 = [1, 2, 3, 4, 5, 6, 7, 8] l2_obj = l2.__iter__() while True: try: i = l2_obj.__next__() print(i) except Exception: break
二、生成器
生成器:生成器本質上是叠代器。
初始生成器:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行
生成器函數定義:
1、一個包含yield關鍵字的函數就是一個生成器函數
2、next 和send 功能一樣,都是執行一次,send獲取下一個值可以給上一個yield賦值。
使用send的註意事項:第一次使用生成器的時候,使用next獲取下一個值,最後一個yield不能接受外部的值
def generator(): print(123) # 123 content = yield 1 print(content) # hello print(456) #456 yield 2 g = generator() g.__next__() g.send(‘hello‘)
三、列表推導式和生成器表達式
1、列表推導式:用列表推導式能夠構建的任何列表,用別的都可以構建,一目了然,占內存。
l2 = [i*i for i in range(1,11)] print(l2) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
2、生成器表達式:類似於列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建一個結果列表,不易看出,節省內存。
l_obj = (‘python%s期‘ % i for i in range(1,12)) print(l_obj) # <generator object <genexpr> at 0x000001AAF0AEBDB0> print(l_obj.__next__()) # python1期 print(l_obj.__next__()) # python2期 print(l_obj.__next__()) # python3期
總結:
1.把列表解析的[]換成()得到的就是生成器表達式
2.列表解析與生成器表達式都是一種便利的編程方式,只不過生成器表達式更節省內存
3.Python不但使用叠代器協議,讓for循環變得更加通用。大部分內置函數,也是使用叠代器協議訪問對象的。例如, sum函數是Python的內置函數,該函數使用叠代器協議訪問對象,而生成器實現了叠代器協議,所以,我們可 以直接這樣計算一系列值的和:
五、內置函數
六、匿名函數
七、遞歸函數
函數部分總結