目錄 1、函數對象 2、函數嵌套 3、閉包函數 3.1 什麼是閉包函數 3.2 如何定義閉包函數 3.3 為何要有閉包函數——閉包函數的應用場景 1、函數對象 函數對象:指的是函數可以被當做’數據’來處理。 具體可以分為四個方面的使用: (1)函數可以被引用 (2)函數可以作為容器類型的元素 (3) ...
目錄
1、函數對象
2、函數嵌套
3、閉包函數
3.1 什麼是閉包函數
3.2 如何定義閉包函數
3.3 為何要有閉包函數——閉包函數的應用場景
1、函數對象
函數對象:指的是函數可以被當做’數據’來處理。
# func=記憶體地址 def func(): print('from func')
func()
輸出結果: from func
具體可以分為四個方面的使用:
(1)函數可以被引用
# func=記憶體地址 def func(): print('from func') f=func # 將func的記憶體地址傳給 f print(f,func) #輸出的是 f func 的記憶體地址 f() #調用函數 f
輸出結果:
<function func at 0x000001CF11CCA0D0> <function func at 0x000001CF11CCA0D0>
from func
(2)函數可以作為容器類型的元素
# func=記憶體地址 def func(): print('from func') l=[func,] print(l) l[0]() dic={'k1':func} print(dic) dic['k1']() 輸出結果: [<function func at 0x000001B6BC12A0D0>] from func {'k1': <function func at 0x000001B6BC12A0D0>} from func
(3)函數可以作為參數傳入另外一個函數
def func(): print('from func') def foo(x): # foo(func), x = func的記憶體地址 print(x) #先輸出func 的記憶體地址 x() # x=func的記憶體地址,x()相當於 func() foo(func) # foo(func的記憶體地址) #調用函數foo 輸出結果: <function func at 0x000001C3AEF4A0D0> from func
# func=記憶體地址 def func(): print('from func') def foo(x): # x = func的記憶體地址 # print(x) x() foo(func) #即 foo(func的記憶體地址) 輸出結果: from func
(4)函數的返回值可以是一個函數
# func=記憶體地址 def func(): print('from func') def foo(x): # x=func的記憶體地址 return x # return func的記憶體地址 res=foo(func) # foo(func的記憶體地址) print(res) # res=func的記憶體地址 res() 輸出結果: <function func at 0x000001C3AEF4A0D0> from func
2、函數的嵌套
(1)函數的嵌套定義:在函數內定義其他函數
def f1(): def f2(): pass
(2)函數的嵌套調用:在調用一個函數的過程中又調用其他函數
def max2(x,y): if x > y: return x else: return y def max4(a,b,c,d): # 第一步:比較a,b得到res1 res1=max2(a,b) # 第二步:比較res1,c得到res2 res2=max2(res1,c) # 第三步:比較res2,d得到res3 res3=max2(res2,d) return res3 res=max4(1,2,3,4) print(res)
好大一顆慄子:
# 圓形 # 求圓形的求周長:2*pi*radius def circle(radius,action=0): from math import pi def perimiter(radius): return 2*pi*radius # 求圓形的求面積:pi*(radius**2) def area(radius): return pi*(radius**2) if action == 0: return 2*pi*radius elif action == 1: return area(radius) circle(33,action=0)
3、閉包函數
【大前提】
基於函數對象的概念,可以將函數返回到任意位置去調用,
但作用域的關係是在定義完函數時就已經被確定了的,與函數的調用位置無關。
也就是說函數被當做數據處理時,始終以自帶的作用域為準。
閉包函數=名稱空間與作用域+函數嵌套+函數對象
核心點:名字的查找關係是以函數定義階段為準
(1)什麼是【閉包函數】
函數被當做數據處理時,始終以自帶的作用域為準。若內嵌函數包含對外部函數作用域(而非全局作用域)中變數的引用,那麼該’內嵌函數’就是閉包函數,簡稱閉包(closures)。
"閉"函數指的該函數是內嵌函數
"包"函數指的該函數包含對外層函數作用功能變數名稱字的引用(不是對全局作用域)
因而無論在何處調用閉包函數,使用的仍然是包裹在其外層的變數。
x=1 def outer(): x=2 def inner(): print(x) return inner func=outer() func() # 結果為2
可以通過函數的closure屬性,查看到閉包函數所包裹的外部變數。
>>> func.__closure__ (<cell at 0x10212af78: int object at 0x10028cca0>,) >>> func.__closure__[0].cell_contents 2
(2) 如何定義閉包函數
1)閉包函數:名稱空間與作用域的應用+函數嵌套
def f1(): x = 33333333333333333333 def f2(): print(x) f2() x=11111 def bar(): x=444444 f1() def foo(): x=2222 bar() foo() 輸出結果: 33333333333333333333
2)閉包函數:函數對象
def f1(): x = 33333333333333333333 def f2(): print('函數f2:',x) return f2 f=f1() # print(f) # x=4444 # f() def foo(): x=5555 f() foo() 輸出結果: 函數f2: 33333333333333333333
(3)為何要有閉包函數——閉包函數的應用
兩種為函數體傳參的方式:
方式一:直接把函數體需要的參數定義成形參
def f2(x): print(x) f2(1) f2(2) f2(3)
方式二:將值包給函數
def f1(x): # x=3 x=3 def f2(): print(x) return f2 x=f1(3) print(x) x()
又有好大一顆慄子:
import requests # 需要事先下載函數模板 傳參的方案一: def get(url): response=requests.get(url) print(len(response.text)) get('https://www.baidu.com') get('https://www.cnblogs.com/linhaifeng') get('https://zhuanlan.zhihu.com/p/109056932') 傳參的方案二: def outter(url): # url='https://www.baidu.com' def get(): response=requests.get(url) print(len(response.text)) return get baidu=outter('https://www.baidu.com') baidu() cnblogs=outter('https://www.cnblogs.com/linhaifeng') cnblogs() zhihu=outter('https://zhuanlan.zhihu.com/p/109056932') zhihu()
閉包函數的這種特性有時又稱為惰性計算。使用將值包給函數的方式,在下一篇博客介紹的裝飾器中也將大有用處。