一、裝飾器前戲之閉包
閉包是函數式編程的重要語法結構
定義:如果在一個內部函數裏,對在外部作用域(但不是在全局作用域)的變量進行引用,那麼內部函數被認爲是閉包。
def f():
c = 5
f()
print(c) ##NameError: name 'c' is not defined
def outer():
x = 10
def inner(): ##條件一 inner就是內部函數
print(x) ##條件二 外部環境的一個變量
return inner ##結論:內部函數inner就是一個閉包
f=outer()
f() ## 10
閉包= 函數快+定義函數時的環境
二、裝飾器高潮
2.1 #遵守封閉與開放原則
import time
def foo():
start = time.time()
print('foo...')
time.sleep(2)
end = time.time()
print('spend %s' % (end-start))
foo() ##foo... spend 2.0003113746643066
如果有多個函數需要計算時間,每一個函數都像上述所做,會引起代碼重複。
import time
def foo():
print('foo...')
time.sleep(2)
def showtime(f):
start = time.time()
f()
end = time.time()
print('spend %s' % (end-start))
showtime(foo)
但是這種方法確是改變了函數的調用方式。
import time
def foo():
print('foo...')
time.sleep(2)
def showtime(f):
def inner():
start = time.time()
f()
end = time.time()
print('spend %s' % (end-start))
return inner
foo=showtime(foo) ##此時輸出的是inner的內存地址
foo() ##相當於執行的是inner函數,閉包
import time
def showtime(f):
def inner():
start = time.time()
f()
end = time.time()
print('spend %s' % (end-start))
return inner
@showtime ##foo=showtime(foo) ##此時輸出的是inner的內存地址
def foo():
print('foo...')
time.sleep(2)
foo() ##相當於執行的是inner函數,閉包
2.2 裝飾器之被裝飾函數的參數
import time
def showtime(f):
def inner(x, y):
start = time.time()
f(x, y)
end = time.time()
print('spend %s' % (end-start))
return inner
@showtime ##add=showtime(add) ##此時輸出的是inner的內存地址
def add(a, b):
print(a+b)
time.sleep(1)
add(1,2) ##相當於執行的是inner函數,閉包
import time
def logger(flag=''):
def showtime(f):
def inner(x, y):
start = time.time()
f(x, y)
end = time.time()
print('spend %s' % (end-start))
if flag=='true':
print('rizhijilu')
return inner
return showtime
@logger('true')##先執行logger函數,==@showtime,返回函數對象的內存地址
def add(a, b):
print(a+b)
time.sleep(1)
add(1,2) ##相當於執行的是inner函數,閉包
@logger('000')
def bar():
print('bar...')
time.sleep(2)
bar()
2.3 裝飾器應用
比如京東,第一次登陸後,之後點其他京東頁面,不需要登陸。
在裝飾器裏,一方面檢測狀態,另一方面登陸