函數即變量
定義一個函數就是把函數體給函數名。變量先定義後使用,函數一定要先聲明後調用,只要聲明後調用即可,哪個先定義哪個後定義沒有關係。如圖所示:
高階函數
所謂高階函數就是1. 把一個函數名當作實參傳給另一個參數;2.把函數作爲結果值返回。
1. 傳入參數
# 高階函數
import time
def a():
time.sleep(2)
print("hello,I am a")
def b(fun):
start_time = time.time()
fun() # 此處不要寫成fun
stop_time = time.time()
print("the function time is %s" %(stop_time - start_time))
b(a) # 像變量一樣傳入函數名即可,不要寫成b(a())
2. 返回函數
# 高階函數
import time
def a():
start_time = time.time()
time.sleep(2)
stop_time = time.time()
print("the function time is %s" %(stop_time - start_time))
def b(fun):
return fun # 返回函數
f = b(a) # 當我們調用b(a)時,返回的並不是結果,而是函數本身
f() # 調用函數
嵌套函數
嵌套不等於調用,即:
def b():
def a():
和
def b():
a()
不一樣
可以把內部嵌套函數看作是局部變量。
裝飾器
裝飾器:本質上是函數,功能是裝飾函數,也就是爲其他函數增加新功能。在代碼運行期間動態增加功能的方式叫做裝飾器。
原則:
1.不能修改被裝飾函數的源代碼。
2.不能修改被裝飾函數的調用方式。
裝飾器 = 高階函數 + 嵌套函數
import time
import functools
def b(func):
@functools.wraps(func)
def a():
start_time = time.time()
func()
stop_time = time.time()
print("the function time is %s" %(stop_time - start_time))
return a
@b # old = b(old)
def old(): # 被裝飾函數
time.sleep(2)
print("hello,我是原來函數")
old()
滿足了不改動原函數和調用方法的原則。
閉包
其實用的還是高階函數,不是立馬返回結果,而是返回函數本身。
1.
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
在函數lazy_sum中又定義了函數sum,並且,內部函數sum可以引用外部函數lazy_sum的參數和局部變量,當lazy_sum返回函數sum時,相關參數和變量都保存在返回的函數中,這種稱爲“閉包(Closure)”。
我們調用lazy_sum()時,每次調用都會返回一個新的函數,即使傳入相同的參數。返回的函數並沒有立刻執行,而是直到調用了纔會執行。
2.
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count() # 列表裏的三個函數,調用時纔會執行
print(f1())
print(f2())
print(f3())
結果並不是1,4,9,原因就在於返回的函數引用了變量i,但它並非立刻執行,等到3個函數都返回時,它們所引用的變量i已經變成了3,因此最終結果都爲9。