1.函數名做用html
函數名本質上就是函數的內存地址或對象。 1.能夠被引用 2.能夠被看成容器類型的元素 3.能夠看成函數的參數和返回值 4.若是記不住的話,那就記住一句話,就當普通變量用
2.閉包python
什麼叫作閉包? 1.必須是嵌套函數 2.在嵌套函數的內部的函數可使用外部的變量(非全局變量)
閉包的特性?
1.python中的閉包會出現內存駐留,普通函數執行一次內存開闢的空間就銷燬了。(此處記錄一下:不是開闢的內存空間銷燬了,是命名空間存放的變量名和值的映射關係銷燬了,而開闢的空間的值還在!)
2.閉包會出現內存泄漏的問題
3.裝飾器的本質就是閉包(面試必問)
閉包的經常使用場景?
咱們知道在函數內的變量在函數外訪問的話,直接調用函數返回就行了,那麼若是咱們想在函數外部來調用內部的函數該怎麼作那?
直接在調用函數是返回函數的名字就能夠了
閉包的優勢:
全局裏存放會有污染和不安全的現象,只能內部訪問外部,不能外部訪問內部,保證數據安全
def wrapper(): money =10 def inner(num): nonlocal money money +=num print(money) print(inner.__closure__) #不返回none的話就是閉包 return inner wrapper()(100)
3.迭代器面試
在之前都聽過迭代對象,能被for循環的就是可迭代對象,包括字符串、列表、元組、字典、集合均可以被for循環,說明他們都是可迭代的。
那咱們要怎樣證實那?
上面說,能被for循環的就是「可迭代的」,可是若是正着想,for怎麼知道誰是可迭代的呢?
由於他們都遵循了可迭代協議,那什麼又是可迭代協議呢?
能夠被迭代要知足的要求就叫作可迭代協議。可迭代協議的定義很是簡單,就是內部實現了__iter__方法。(可迭代的對象內部必須含有一個__iter__方法,才能叫可迭代對象,也就能獲得相應的迭代器)
查看一個數據類型是不是可迭代的方法:
1.dir(li)
li=[1,2,3]
print(dir(li))
若是裏面包含__iter__方法就證實是可迭代對象,遵循可迭代協議
2.
l = [1,2,3]
l_iter = l.__iter__()
from collections import Iterable
from collections import Iterator
print(isinstance(l,Iterable)) #True #查看是否是可迭代對象
print(isinstance(l,Iterator)) #False #查看是否是迭代器
經過"a = 對象.__iter__ # 建立一個迭代器",經過迭代器內部的__next__方法獲得下一個迭代器元素,這就是for循環的工做機制!
使用while循環和迭代器來模擬for循環
lst = [6,5,4] l = lst.__iter__() while True: try: i = l.__next__() print(i) except StopIteration: break
注意: 迭代器不能反覆,只能向下執行
總結:
Iterable: 可迭代對象. 內部包含__iter__()函數
Iterator: 迭代器. 內部包含__iter__() 同時包含__next__().
迭代器的特色:
1. 節省內存.
2. 惰性機制
3. 不能反覆, 只能向下執行.
4.提供一種不依賴索取值的方法,經過__next__()方法取值編程
缺點:
1.取值不如索引方便
2.惰性機制,用一個取值一個安全
for循環本質:
for循環就是基於迭代器協議提供了一個統一的能夠遍歷全部對象的方法,即在遍歷以前,先調用對象的__iter__方法將其轉換成一個迭代器,
而後使用迭代器協議去實現循環訪問,這樣全部的對象就均可以經過for循環來遍歷了數據結構
4.遞歸函數閉包
在函數內部,能夠調用其餘函數。若是一個函數在內部調用自身自己,這個函數就是遞歸函數(必須有跳出條件)。app
舉個例子,咱們來計算階乘n! = 1 x 2 x 3 x ... x n,用函數fact(n)表示,能夠看出:
fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n
因此,fact(n)能夠表示爲n x fact(n-1),只有n=1時須要特殊處理。
編程語言
因而,fact(n)用遞歸的方式寫出來就是:
def fact(n):
if n==1:
return 1
return n * fact(n - 1)函數
遞歸函數的優勢是定義簡單,邏輯清晰。理論上,全部的遞歸函數均可以寫成循環的方式,但循環的邏輯不如遞歸清晰。
使用遞歸函數須要注意防止棧溢出。在計算機中,函數調用是經過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。
因爲棧的大小不是無限的,因此,遞歸調用的次數過多,會致使棧溢出。能夠試試fact(1000)!
解決遞歸調用棧溢出的方法是經過尾遞歸優化,事實上尾遞歸和循環的效果是同樣的,因此,把循環當作是一種特殊的尾遞歸函數也是能夠的。
尾遞歸是指,在函數返回的時候,調用自身自己,而且,return語句不能包含表達式。這樣,編譯器或者解釋器就能夠把尾遞歸作優化,使遞歸自己不管調用多少次,都只佔用一個棧幀,不會出現棧溢出的狀況。
總結:
使用遞歸函數的優勢是邏輯簡單清晰,缺點是過深的調用會致使棧溢出。
針對尾遞歸優化的語言能夠經過尾遞歸防止棧溢出。尾遞歸事實上和循環是等價的,沒有循環語句的編程語言只能經過尾遞歸實現循環。
Python標準的解釋器沒有針對尾遞歸作優化,任何遞歸函數都存在棧溢出的問題。
應用場景:在不知道循環的具體次數的時候使用遞歸
調整遞歸最大深度
import sys
sys.setrecursionlimit(10000)