函数闭包与装饰器
一 什么是裝飾器
裝飾器即函數(shù)
裝飾即修飾,意指為其他函數(shù)添加新功能
裝飾器定義:本質(zhì)就是函數(shù),功能是為其他函數(shù)添加新功能
二 裝飾器需要遵循的原則
1.不修改被裝飾函數(shù)的源代碼(開放封閉原則)
2.為被裝飾函數(shù)添加新功能后,不修改被修飾函數(shù)的調(diào)用方式
三 實(shí)現(xiàn)裝飾器知識(shí)儲(chǔ)備
裝飾器=高階函數(shù)+函數(shù)嵌套+閉包
四 高階函數(shù)
高階函數(shù)定義:
1.函數(shù)接收的參數(shù)是一個(gè)函數(shù)名
2.函數(shù)的返回值是一個(gè)函數(shù)名
3.滿足上述條件任意一個(gè),都可稱之為高階函數(shù)
#1、函數(shù)接收的參數(shù)是一個(gè)函數(shù)名:保證函數(shù)源代碼不被修改 import time def foo():time.sleep(3)print('你好啊林師傅')def test(func): #test形參接收了函數(shù)名,為高階函數(shù)。func為函數(shù)的內(nèi)存地址# print(func) #打印出來的是內(nèi)存地址start_time=time.time()func() #直接運(yùn)行foo函數(shù)stop_time = time.time()print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time)) # foo() test(foo)# 2、高階函數(shù)的返回值也是一個(gè)函數(shù)名,函數(shù)的調(diào)用方式也不用修改了 def foo():print('from the foo') def test(func):return func res=test(foo) #從而func就是foo內(nèi)存地址 # print(res) res() #函數(shù)直接就運(yùn)行了#進(jìn)一步取消res,就用原來的foo名字 foo=test(foo) # # print(res) foo() # 不改變函數(shù)調(diào)用方式#########整合版本1 import time def foo():time.sleep(3)print('來自foo')#不修改foo源代碼 #不修改foo調(diào)用方式 #多運(yùn)行了一次,不合格 def timer(func): #參數(shù)為函數(shù)名start_time=time.time()func() #return func如果換到這里來,并沒有給原函數(shù)添加任何功能。stop_time = time.time()print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time))return func #返回值為函數(shù)名 foo=timer(foo) #賦給foo,執(zhí)行了一遍 foo() #直接調(diào)用foo,又執(zhí)行了一遍foo。只能改return ##結(jié)果: 來自foo 函數(shù)運(yùn)行時(shí)間是 3.0001756482365 來自foo #多打印了一個(gè) #高階函數(shù)沒辦法正常運(yùn)行且順利添加新功能 #1、函數(shù)接收的參數(shù)是一個(gè)函數(shù)名:保證函數(shù)源代碼不被修改 import time def foo():time.sleep(3)print('你好啊林師傅')def test(func): #test形參接收了函數(shù)名,為高階函數(shù)。func為函數(shù)的內(nèi)存地址# print(func) #打印出來的是內(nèi)存地址start_time=time.time()func() #直接運(yùn)行foo函數(shù)stop_time = time.time()print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time)) # foo() test(foo)# 2、高階函數(shù)的返回值也是一個(gè)函數(shù)名,函數(shù)的調(diào)用方式也不用修改了 def foo():print('from the foo') def test(func):return func res=test(foo) #從而func就是foo內(nèi)存地址 # print(res) res() #函數(shù)直接就運(yùn)行了#進(jìn)一步取消res,就用原來的foo名字 foo=test(foo) # # print(res) foo() # 不改變函數(shù)調(diào)用方式#########整合版本1 import time def foo():time.sleep(3)print('來自foo')#不修改foo源代碼 #不修改foo調(diào)用方式 #多運(yùn)行了一次,不合格 def timer(func): #參數(shù)為函數(shù)名start_time=time.time()func() #return func如果換到這里來,并沒有給原函數(shù)添加任何功能。stop_time = time.time()print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time))return func #返回值為函數(shù)名 foo=timer(foo) #賦給foo,執(zhí)行了一遍 foo() #直接調(diào)用foo,又執(zhí)行了一遍foo。只能改return ##結(jié)果: 來自foo 函數(shù)運(yùn)行時(shí)間是 3.0001756482365 來自foo #多打印了一個(gè) #高階函數(shù)沒辦法正常運(yùn)行且順利添加新功能 #1、函數(shù)接收的參數(shù)是一個(gè)函數(shù)名:保證函數(shù)源代碼不被修改 import time def foo():time.sleep(3)print('你好啊林師傅')def test(func): #test形參接收了函數(shù)名,為高階函數(shù)。func為函數(shù)的內(nèi)存地址# print(func) #打印出來的是內(nèi)存地址start_time=time.time()func() #直接運(yùn)行foo函數(shù)stop_time = time.time()print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time)) # foo() test(foo)# 2、高階函數(shù)的返回值也是一個(gè)函數(shù)名,函數(shù)的調(diào)用方式也不用修改了 def foo():print('from the foo') def test(func):return func res=test(foo) #從而func就是foo內(nèi)存地址 # print(res) res() #函數(shù)直接就運(yùn)行了#進(jìn)一步取消res,就用原來的foo名字 foo=test(foo) # # print(res) foo() # 不改變函數(shù)調(diào)用方式#########整合版本1 import time def foo():time.sleep(3)print('來自foo')#不修改foo源代碼 #不修改foo調(diào)用方式 #多運(yùn)行了一次,不合格 def timer(func): #參數(shù)為函數(shù)名start_time=time.time()func() #return func如果換到這里來,并沒有給原函數(shù)添加任何功能。stop_time = time.time()print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time))return func #返回值為函數(shù)名 foo=timer(foo) #賦給foo,執(zhí)行了一遍 foo() #直接調(diào)用foo,又執(zhí)行了一遍foo。只能改return ##結(jié)果: 來自foo 函數(shù)運(yùn)行時(shí)間是 3.0001756482365 來自foo #多打印了一個(gè) #高階函數(shù)沒辦法正常運(yùn)行且順利添加新功能 #1、函數(shù)接收的參數(shù)是一個(gè)函數(shù)名:保證函數(shù)源代碼不被修改 import time def foo():time.sleep(3)print('你好啊林師傅')def test(func): #test形參接收了函數(shù)名,為高階函數(shù)。func為函數(shù)的內(nèi)存地址# print(func) #打印出來的是內(nèi)存地址start_time=time.time()func() #直接運(yùn)行foo函數(shù)stop_time = time.time()print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time)) # foo() test(foo)# 2、高階函數(shù)的返回值也是一個(gè)函數(shù)名,函數(shù)的調(diào)用方式也不用修改了 def foo():print('from the foo') def test(func):return func res=test(foo) #從而func就是foo內(nèi)存地址 # print(res) res() #函數(shù)直接就運(yùn)行了#進(jìn)一步取消res,就用原來的foo名字 foo=test(foo) # # print(res) foo() # 不改變函數(shù)調(diào)用方式#########整合版本1 import time def foo():time.sleep(3)print('來自foo')#不修改foo源代碼 #不修改foo調(diào)用方式 #多運(yùn)行了一次,不合格 def timer(func): #參數(shù)為函數(shù)名start_time=time.time()func() #return func如果換到這里來,并沒有給原函數(shù)添加任何功能。stop_time = time.time()print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time))return func #返回值為函數(shù)名 foo=timer(foo) #賦給foo,執(zhí)行了一遍 foo() #直接調(diào)用foo,又執(zhí)行了一遍foo。只能改return ##結(jié)果: 來自foo 函數(shù)運(yùn)行時(shí)間是 3.0001756482365 來自foo #多打印了一個(gè) #高階函數(shù)沒辦法正常運(yùn)行且順利添加新功能 #1、函數(shù)接收的參數(shù)是一個(gè)函數(shù)名:保證函數(shù)源代碼不被修改 import time def foo():time.sleep(3)print('你好啊林師傅')def test(func): #test形參接收了函數(shù)名,為高階函數(shù)。func為函數(shù)的內(nèi)存地址# print(func) #打印出來的是內(nèi)存地址start_time=time.time()func() #直接運(yùn)行foo函數(shù)stop_time = time.time()print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time)) # foo() test(foo)# 2、高階函數(shù)的返回值也是一個(gè)函數(shù)名,函數(shù)的調(diào)用方式也不用修改了 def foo():print('from the foo') def test(func):return func res=test(foo) #從而func就是foo內(nèi)存地址 # print(res) res() #函數(shù)直接就運(yùn)行了#進(jìn)一步取消res,就用原來的foo名字 foo=test(foo) # # print(res) foo() # 不改變函數(shù)調(diào)用方式#########整合版本1 import time def foo():time.sleep(3)print('來自foo')#不修改foo源代碼 #不修改foo調(diào)用方式 #多運(yùn)行了一次,不合格 def timer(func): #參數(shù)為函數(shù)名start_time=time.time()func() stop_time = time.time()print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time))return func #返回值為函數(shù)名 foo=timer(foo) #賦給foo,執(zhí)行了一遍 foo() #直接調(diào)用foo,又執(zhí)行了一遍foo。只能改return ##結(jié)果: 來自foo 函數(shù)運(yùn)行時(shí)間是 3.0001756482365 來自foo #多打印了一個(gè) #高階函數(shù)沒辦法正常運(yùn)行且順利添加新功能#沒有修改被修飾函數(shù)的源代碼,也沒有修改被修飾函數(shù)的調(diào)用方式,但是也沒有為被修飾函數(shù)添加新功能
def timer(func):
start_time=time.time()
return func #return func如果換到這里來,并沒有給原函數(shù)添加任何功能。
stop_time = time.time()
print('函數(shù)運(yùn)行時(shí)間是 %s' % (stop_time-start_time)
foo=timer(foo)
foo()
高階函數(shù)總結(jié)
1.函數(shù)接收的參數(shù)是一個(gè)函數(shù)名
作用:在不修改函數(shù)源代碼的前提下,為函數(shù)添加新功能,
不足:會(huì)改變函數(shù)的調(diào)用方式
2.函數(shù)的返回值是一個(gè)函數(shù)名
作用:不修改函數(shù)的調(diào)用方式
不足:不能添加新功能
五 函數(shù)嵌套
# 函數(shù)嵌套:在一個(gè)函數(shù)中重新定義一個(gè)新的函數(shù) def foo():print('from foo')def test():passdef father(auth_type):# print('from father %s' %name)def son():# name='linhaifeng_1'# print('我的爸爸是%s' %name)def grandson():print('我的爺爺是%s' %auth_type) #在上上級(jí)找,在最外層傳,這里也能收到grandson() #運(yùn)行函數(shù)# print(locals()) #打印當(dāng)前層的局部變量:name,son函數(shù)也是 son() # father('linhaifeng') father('filedb')六 閉包 1 '''2 閉包:在一個(gè)作用域里放入定義變量,相當(dāng)于打了一個(gè)包3 '''4 def father(name):5 def son():6 # name='alex'7 print('我爸爸是 [%s]' %name)8 def grandson():9 # name='wupeiqi' 10 print('我爺爺是 [%s]' %name) 11 grandson() 12 son() 13 14 father('林海峰') #裝飾器實(shí)現(xiàn)
import time def timmer(func): #func=testdef wrapper():# print(func)start_time=time.time()func() #就是在運(yùn)行test()stop_time = time.time()print('運(yùn)行時(shí)間是%s' %(stop_time-start_time))return wrapper@timmer #test=timmer(test) def test():time.sleep(3)print('test函數(shù)運(yùn)行完畢') test()res=timmer(test) #返回的是wrapper的地址 res() #執(zhí)行的是wrapper() test=timmer(test) #返回的是wrapper的地址 test() #執(zhí)行的是wrapper() @timmer 就相當(dāng)于 test=timmer(test)
七 無參裝飾器
#補(bǔ)充知識(shí):用解壓的方式取出一個(gè)列表的最開頭和結(jié)尾 #比索引略微簡潔一些,有的時(shí)候適用 #例1: a,b,c='hel' >>>a 'h' >>>b 'e' >>>c 'l' #例2:a表示列表第一個(gè),c表示最后一個(gè) l=[0,2,3,445,67,8,9,92,2,1] >>>a.*_.c=l #下劃線表示中間所有元素的變量名,可以隨便起,*m也可以 >>>a '0' >>>c '1' #例3:取出頭尾兩個(gè) >>>a,b.*_.c,d=l #對(duì)比索引:a,d=l[0],l[-1]無參裝飾器=高級(jí)函數(shù)+函數(shù)嵌套
基本框架
1 #這就是一個(gè)實(shí)現(xiàn)一個(gè)裝飾器最基本的架子 2 def timer(func): #func就相當(dāng)于你輸入的test函數(shù) 3 def wrapper():4 print(func) #函數(shù)嵌套 4 func() 5 return wrapper
加上參數(shù)
1 def timer(func): 2 def wrapper(*args,**kwargs): 3 func(*args,**kwargs) 4 return wrapper加上功能
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 func(*args,**kwargs) 6 stop_time=time.time() 7 print('函數(shù)[%s],運(yùn)行時(shí)間是[%s]' %(func,stop_time-start_time)) 8 return wrapper加上返回值
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 res=func(*args,**kwargs) 6 stop_time=time.time() 7 print('函數(shù)[%s],運(yùn)行時(shí)間是[%s]' %(func,stop_time-start_time)) 8 return res 9 return wrapper使用裝飾器
1 def cal(array): 2 res=0 3 for i in array: 4 res+=i 5 return res 6 7 cal=timer(cal) 8 cal(range(10))語法糖@
1 @timer #@timer就等同于cal=timer(cal) 2 def cal(array): 3 res=0 4 for i in array: 5 res+=i 6 return res 7 8 cal(range(10))八 裝飾器應(yīng)用示例
# 京東登錄(無參數(shù)) # 利用用戶列表,for循環(huán)來遍歷該字典 user_list=[{'name':'alex','passwd':'123'},{'name':'linhaifeng','passwd':'123'},{'name':'wupeiqi','passwd':'123'},{'name':'yuanhao','passwd':'123'}, ] current_dic={'username':None,'login':False} #記錄下當(dāng)前用戶的狀態(tài)#加上認(rèn)證功能的裝飾器函數(shù):參數(shù)、返回值 #登錄一次之后,不用每次都再輸。應(yīng)該記錄下登錄一次的狀態(tài)(用一個(gè)全局變量來實(shí)現(xiàn)) def auth_func(func): #函數(shù)名def wrapper(*args,**kwargs):if auth_type == 'filedb': if current_dic['username'] and current_dic['login']:res = func(*args, **kwargs)return resusername=input('用戶名:').strip()passwd=input('密碼:').strip()for user_dic in user_list: #遍歷列表中所有記錄是否與輸入的名字密碼匹配if username == user_dic['name'] and passwd == user_dic['passwd']:current_dic['username']=username #記錄下登錄的狀態(tài):拿的就是全局變量的引用current_dic['login']=Trueres = func(*args, **kwargs) #驗(yàn)證成功了才可以直接運(yùn)行函數(shù)return res #wrapper函數(shù)直接結(jié)束,不必再加break語句了else:print('用戶名或者密碼錯(cuò)誤') #此else與for連用,不是循環(huán)一次后的if連用。列表中用戶名和密碼全for循環(huán)完畢了return wrapperreturn auth_func@auth def index(): #已經(jīng)輸入正確用戶名及密碼了print('歡迎來到京東主頁')@authdef home(name):print('歡迎回家%s' %name) @authdef shopping_car(name):print('%s的購物車?yán)镉?#xff3b;%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))print('before-->',current_dic) index() print('after--->',current_dic) home('產(chǎn)品經(jīng)理') shopping_car('產(chǎn)品經(jīng)理') user_list=[{'name':'alex','passwd':'123'},{'name':'linhaifeng','passwd':'123'},{'name':'wupeiqi','passwd':'123'},{'name':'yuanhao','passwd':'123'}, ]current_user={'username':None,'login':False} def auth(auth_type='file'):def auth_deco(func):def wrapper(*args,**kwargs):if auth_type == 'file':if current_user['username'] and current_user['login']:res=func(*args,**kwargs)return resusername=input('用戶名: ').strip()passwd=input('密碼: ').strip()for index,user_dic in enumerate(user_list):if username == user_dic['name'] and passwd == user_dic['passwd']:current_user['username']=usernamecurrent_user['login']=Trueres=func(*args,**kwargs)return resbreakelse:print('用戶名或者密碼錯(cuò)誤,重新登錄')elif auth_type == 'ldap':print('巴拉巴拉小魔仙')res=func(*args,**kwargs)return resreturn wrapperreturn auth_deco#auth(auth_type='file')就是在運(yùn)行一個(gè)函數(shù),然后返回auth_deco,所以@auth(auth_type='file') #就相當(dāng)于@auth_deco,只不過現(xiàn)在,我們的auth_deco作為一個(gè)閉包的應(yīng)用,外層的包auth給它留了一個(gè)auth_type='file'參數(shù) @auth(auth_type='ldap') def index():print('歡迎來到主頁面')@auth(auth_type='ldap') def home():print('這里是你家')def shopping_car():print('查看購物車啊親')def order():print('查看訂單啊親')# print(user_list) index() # print(user_list) home()?裝飾器運(yùn)行流程
import time def timmer(func): #func=test1 第二步 # wrapper中參數(shù)數(shù)目不要寫死,用列表裝def wrapper(*args,**kwargs): #第五步 #test('linhaifeng',age=18) 元祖args=('linhaifeng') kwargs={'age':18}start_time=time.time() #第六步 res=func(*args,**kwargs) #第七步,接著去找test函數(shù)定義去了 就是在運(yùn)行test() func(*('linhaifeng'),**{'age':18})#wrapper中怎么接收的就怎么傳給funcstop_time = time.time() #第十二步print('運(yùn)行時(shí)間是%s' %(stop_time-start_time)) #第十三步return res ##第十四步 加入返回值,結(jié)束wrapperreturn wrapper #第三步 @timmer #test=timmer(test) #第一步:運(yùn)行這個(gè)執(zhí)行timmer函數(shù),直接返回wrapper地址給test,然后到test()調(diào)用 def test(name,age): #第八步:對(duì)應(yīng)wrapper中形參表也要加time.sleep(3) #第九步print('test函數(shù)運(yùn)行完畢,名字是【%s】 年齡是【%s】' %(name,age)) #第十步return '這是test的返回值' #第十一步 test() #第四步,直接運(yùn)行wrapper函數(shù) # 京東登錄:auth函數(shù)中帶參數(shù):數(shù)據(jù)庫的認(rèn)證類型來源 # 帶參數(shù)的少用,不帶參數(shù)的更加常用 # 利用用戶列表,for循環(huán)來遍歷該字典 # 缺點(diǎn)1、認(rèn)證來源:用戶列表應(yīng)該從數(shù)據(jù)庫里取出來。寫死了數(shù)據(jù)庫 #(可以將user_list寫到文件當(dāng)中便于增刪改。注意提取文件內(nèi)容時(shí)都是得到字符串,用eval剝離出來轉(zhuǎn)化為字典) user_list=[{'name':'alex','passwd':'123'},{'name':'linhaifeng','passwd':'123'},{'name':'wupeiqi','passwd':'123'},{'name':'yuanhao','passwd':'123'}, ] current_dic={'username':None,'login':False} #記錄下當(dāng)前用戶的狀態(tài)#加上認(rèn)證功能的裝飾器函數(shù):參數(shù)、返回值 #登錄一次之后,不用每次都再輸。應(yīng)該記錄下登錄一次的狀態(tài)(用一個(gè)全局變量來實(shí)現(xiàn)) def auth(auth_type='filedb'):def auth_func(func): #函數(shù)名def wrapper(*args,**kwargs):print('認(rèn)證類型是',auth_type) if auth_type == 'filedb': if current_dic['username'] and current_dic['login']:res = func(*args, **kwargs)return resusername=input('用戶名:').strip()passwd=input('密碼:').strip()for user_dic in user_list: #遍歷列表中所有記錄是否與輸入的名字密碼匹配if username == user_dic['name'] and passwd == user_dic['passwd']:current_dic['username']=username #記錄下登錄的狀態(tài):拿的就是全局變量的引用current_dic['login']=Trueres = func(*args, **kwargs) #驗(yàn)證成功了才可以直接運(yùn)行函數(shù)return res #wrapper函數(shù)直接結(jié)束,不必再加break語句了else:print('用戶名或者密碼錯(cuò)誤') #此else與for連用,不是循環(huán)一次后的if連用。列表中用戶名和密碼全for循環(huán)完畢了elif auth_type == 'ldap':print('鬼才特么會(huì)玩')res = func(*args, **kwargs)return reselse:print('鬼才知道你用的什么認(rèn)證方式')res = func(*args, **kwargs)return resreturn wrapperreturn auth_func#對(duì)auth_func添加參數(shù),加括號(hào)相當(dāng)于直接運(yùn)行auth函數(shù),因此在這里向無參數(shù)形式當(dāng)中加入return auth_func @auth(auth_type='filedb') # auth函數(shù)的返回值:auth_func=auth(auth_type='filedb')-->@auth_func 附加了一個(gè)auth_type # --->index=auth_func(index)這個(gè)指向的返回值還是wrapper,繼續(xù)執(zhí)行wrapper def index(): #已經(jīng)輸入正確用戶名及密碼了print('歡迎來到京東主頁')@auth(auth_type='ldap') def home(name): print('歡迎回家%s' %name)@auth(auth_type='sssssss') def shopping_car(name):print('%s的購物車?yán)镉?#xff3b;%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))print('before-->',current_dic) index() print('after--->',current_dic) home('產(chǎn)品經(jīng)理') shopping_car('產(chǎn)品經(jīng)理')?
九 超時(shí)裝飾器
import sys,threading,timeclass KThread(threading.Thread):"""A subclass of threading.Thread, with a kill()method.Come from:Kill a thread in Python:http://mail.python.org/pipermail/python-list/2004-May/260937.html"""def __init__(self, *args, **kwargs):threading.Thread.__init__(self, *args, **kwargs)self.killed = Falsedef start(self):"""Start the thread."""self.__run_backup = self.runself.run = self.__run # Force the Thread to install our trace.threading.Thread.start(self)def __run(self):"""Hacked run function, which installs thetrace."""sys.settrace(self.globaltrace)self.__run_backup()self.run = self.__run_backupdef globaltrace(self, frame, why, arg):if why == 'call':return self.localtraceelse:return Nonedef localtrace(self, frame, why, arg):if self.killed:if why == 'line':raise SystemExit()return self.localtracedef kill(self):self.killed = Trueclass Timeout(Exception):"""function run timeout"""def timeout(seconds):"""超時(shí)裝飾器,指定超時(shí)時(shí)間若被裝飾的方法在指定的時(shí)間內(nèi)未返回,則拋出Timeout異常"""def timeout_decorator(func):"""真正的裝飾器"""def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs))def _(*args, **kwargs):result = []new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list'oldfunc': func,'result': result,'oldfunc_args': args,'oldfunc_kwargs': kwargs}thd = KThread(target=_new_func, args=(), kwargs=new_kwargs)thd.start()thd.join(seconds)alive = thd.isAlive()thd.kill() # kill the child threadif alive:raise Timeout(u'function run too long, timeout %d seconds.' % seconds)else:return result[0]_.__name__ = func.__name___.__doc__ = func.__doc__return _return timeout_decorator@timeout(5)def method_timeout(seconds, text):print('start', seconds, text)time.sleep(seconds)print('finish', seconds, text)return secondsmethod_timeout(6,'asdfasdfasdfas')?
轉(zhuǎn)載于:https://www.cnblogs.com/Josie-chen/p/8707322.html
總結(jié)
- 上一篇: Jquery调用ajax参数说明
- 下一篇: 网站XML格式的网站地图(sitemap