一. 函數名的運用. 函數名是一個變數, 但它是一個特殊的變量, 與括弧配合可以執行函數的變量. 1. 函數名的記憶體地址 2. 函數名可以賦值給其他變量 3. 函數名可以當做容器類的元素 4. 函數名可以當做函數的參數 5. 函數名可以作為函數的返回值 二. 閉包 1. 閉包就是內層函數,對外層函數 ...
一. 函數名的運用.
函數名是一個變數, 但它是一個特殊的變量, 與括弧配合可以執行函數的變量.
1. 函數名的記憶體地址
def func(): print("呵呵") print(func) 結果: <function func at 0x1101e4ea0>
2. 函數名可以賦值給其他變量
def func(): print("呵呵") print(func) a = func # 把函數當成一個變數賦值給另一個變量 a() # 函數調用 func()
3. 函數名可以當做容器類的元素
def func1(): print("呵呵") def func2(): print("呵呵") def func3(): print("呵呵") def func4(): print("呵呵") lst = [func1, func2, func3] for i in lst: i()
4. 函數名可以當做函數的參數
def func(): print("吃了麽") def func2(fn): print("我是func2") fn() # 執行傳遞過來的fn print("我是func2") func2(func) # 把函數func當成參數傳遞給func2的參數fn.
5. 函數名可以作為函數的返回值
def func_1(): print("這里是函數1") def func_2(): print("這里是函數2") print("這里是函數1") return func_2 fn = func_1() # 執行函數1. 函數1返回的是函數2, 這時fn指向的就是上面函數2 fn() # 執行上面返回的函數
二. 閉包
1. 閉包就是內層函數,對外層函數(非全局)的變量的引用叫閉包.
def func1(): name = "alex" def func2(): print(name) # 閉包 func2() func1() 結果: alex
我們可以使用__closure__來檢測函數是否是閉包. 使用函數名.__closure__返回cell就是
2. 閉包返回None就不是閉包
def func1(): name = "alex" def func2(): print(name) # 閉包 func2() print(func2.__closure__) # (<cell at 0x10c2e20a8: str object at 0x10c3fc650>,) func1()
3. 如何在函數外邊調用內部函數呢?
def outer(): name = "alex" # 內部函數 def inner(): print(name) return inner fn = outer() # 訪問外部函數, 獲取到內部函數的函數地址 fn() # 訪問內部函數
4. 如果多層嵌套只需要一層一層的往外層返回就行了
def func1(): def func2(): def func3(): print("嘿嘿") return func3 return func2 func1()()()
5.閉包的優勢:
由於我們在外界可以訪問內部函數. 那這個時候內部函 數訪問的時間和時機就不一定了, 因為在外部,
我可以選擇在任意的時間去訪問內部函數. 這個時候. 想一想. 我們之前說過, 如果一個函數執行完畢.
則這個函數中的變量以及局部命名空間中的內容都將會被銷毀. 在閉包中.如果變量被銷毀,那內部函
數將不能正常執行. 所 以,python規定. 如果你在內部函數中訪問了外層函數中的變量.那麼這個變量
將不會消亡. 將會常駐在記憶體中. 也就是說. 使用閉包,可以保證外層函數中的變量在記憶體中常駐.
註意: 綜上, 閉包的作用就是讓一個變量能夠常駐記憶體. 供後面的程式使用.
三. 迭代器
1. 我們之前一直在用可迭代對象進行迭代操作. 那麼到底什麽是可迭代對象. 本小節主要討論可迭代對象.
首先我們先回顧一下目前我們所熟知的可迭代對象有哪些: str, list, tuple, dict, set. 那為什麽我們可以
稱他們為可迭代對象呢? 因為他們都遵循了可迭代協議. 什麽是可迭代協議.
首先我們先看一段錯誤代碼:
# 對的 s = "abc" for c in s: print(c) # 錯的 for i in 123: print(i) 結果: Traceback (most recent call last): File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 8, in <module> for i in 123: TypeError: 'int' object is not iterable
2. 註意看報錯信息中有這樣一句話. 'int' object is not iterable . 翻譯過來就是整數類型對象是不可迭代的.
iterable表示可迭代的. 表示可迭代協議. 那麼如何進行驗證你的數據類型是否符合可迭代協議.我們可以
通過dir函數來查看類中定義好的所有方法.
s = "我的哈哈哈" print(dir(s)) # 可以列印對象中的方法和函數 print(dir(str)) # 也可以列印類中聲明的方法和函數
在列印結果中. 尋找__iter__ 如果能找到. 那麼這個類的對象就是一個可迭代對象.
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__','__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find',
'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate',
'upper', 'zfill']
我們發現list, tuple, dict, set 可以進行for迴圈的東西都有__iter__函數, 包括range也有我們發現在字元串中
可以找到__iter__.
3. 我們還可以通過isinstence()函數來查 看一個對象是什麽類型的
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 print(isinstance(l_iter,Iterator)) #True print(isinstance(l_iter,Iterable)) #True
綜上. 我們可以確定. 如果對象中有__iter__函數. 那麼我們認為這個對象遵守了可迭代協議. 就可以獲取到相應
的迭代器. 這里的__iter__是幫助我們獲取到對象的迭代器. 我們使用迭代 器中的__next__()來獲取到一個迭代
器中的元素.
4. 那麼我們之前講的for的工作原理到底是什麼?
繼續看代碼
s = "我愛北北京天安⻔門" c = s.__iter__() # 獲取迭代器器 print(c.__next__()) # 使用迭代器進行迭代. 獲取一個元素 我 print(c.__next__()) # 愛 print(c.__next__()) # 北 print(c.__next__()) # 京 print(c.__next__()) # 天 print(c.__next__()) # 安 print(c.__next__()) # 門 print(c.__next__()) # StopIteration
for迴圈的機制:
for i in [1,2,3]: print(i)
5. 使用while迴圈+迭代器來模擬for迴圈(必須要掌握)
lst = [1,2,3] lst_iter = lst.__iter__() while True: try: i = lst_iter.__next__() print(i) except StopIteration: break
總結:
Iterable: 可迭代對象. 內部包含__iter__()函數
Iterator: 迭代器. 內部包含__iter__() 同時包含__next__().
迭代器的特點:
1. 節省記憶體.
2. 惰性機制
3. 不能反覆, 只能向下執行.
我們可以把要迭代的內容當成子彈. 然後呢. 獲取到迭代器__iter__(), 就把子彈都裝在彈夾中. 然後發射
就是__next__()把每一個子彈(元素)打出來. 也就是說,for迴圈的時候.一開始的 時候是__iter__()來獲取
迭代器. 後面每次獲取元素都是通過__next__()來完成的. 當程式遇到 StopIteration將結束迴圈.