1、裝飾器
裝飾器本質是函數,裝飾其他函數,就是爲其他函數添加附加功能。
原則:1.不能修改被裝飾的函數的源代碼
2.不能修改被裝飾的函數的調用方式
實現裝飾器 知識儲備
1.函數即“變量”
2.高階函數
a.把一個函數當作實參傳給另外一個函數(在不修改被裝飾函數源代碼的情況下 爲其添加功能)
b.返回值中包含函數名(不修改函數的調用方式)
3.嵌套函數
高階函數+嵌套函數 = 裝飾器
高階函數#變量可以指向函數,函數的參數能接收變量,那麼一個函數就可以接收另一個函數作爲參數,這種函數就稱之爲高階函數。 嵌套函數:在一個函數體內創建另外一個函數,這種函數就叫內嵌函數(基於python支持靜態嵌套域)
知識回顧
高階函數
def bar(): print ("in the bar") def foo(func): res=func() return res foo(bar)
#!/usr/bin/env python #-*- coding:utf-8 -*- # Author:DCCimport import time def bar(): time.sleep(2) print("in the bar") def test1(func): start_time=time.time() func() stop_time=time.time() print("run time is %s" %(stop_time-start_time)) test1(bar)
嵌套函數
y = 10 # def test(): # y+=1 # print y def test(): # global y y = 2 print(y) test() print(y) def dad(): m = 1 def son(): n = 2 print('--->', m + n) print('-->',m) son() dad()
注:函數是存在內存中的,只有退出程序後函數才從內存中刪除。如果想刪除內存中的函數,用del
匿名函數
lambda x:x*3 calc = lambda x:x*3 print(calc(3))
運行結果:
9
裝飾器
(1)單獨以f1爲例:
def w1(func): def inner(): # 驗證1 # 驗證2 # 驗證3 return func() return inner @w1 def f1(): print 'f1'
當寫完這段代碼後(函數未被執行、未被執行、未被執行),python解釋器就會從上到下解釋代碼,步驟如下:
def w1(func): ==>將w1函數加載到內存
@w1
沒錯,從表面上看解釋器僅僅會解釋這兩句代碼,因爲函數在沒有被調用之前其內部代碼不會被執行。
從表面上看解釋器着實會執行這兩句,但是 @w1 這一句代碼裏卻有大文章,@函數名 是python的一種語法糖。
如上例@w1內部會執行一下操作:
執行w1函數,並將 @w1 下面的 函數 作爲w1函數的參數,即:@w1 等價於 w1(f1)
所以,內部就會去執行:
def inner:
#驗證
return f1() # func是參數,此時 func 等於 f1
return inner # 返回的 inner,inner代表的是函數,非執行函數
其實就是將原來的 f1 函數塞進另外一個函數中將執行完的 w1 函數返回值賦值給@w1下面的函數的函數名
w1函數的返回值是:
def inner:
#驗證
return 原來f1() # 此處的 f1 表示原來的f1函數
然後,將此返回值再重新賦值給 f1,即:
新f1 = def inner:
#驗證
return 原來f1()
所以,以後業務部門想要執行 f1 函數時,就會執行 新f1 函數,在 新f1 函數內部先執行驗證,再執行原來的f1函數,然後將 原來f1 函數的返回值 返回給了業務調用者。
如此一來, 即執行了驗證的功能,又執行了原來f1函數的內容,並將原f1函數返回值 返回給業務調用着
(2)問答時間
問題:一個函數可以被多個裝飾器裝飾嗎?
def w1(func): def inner(*args,**kwargs): # 驗證1 # 驗證2 # 驗證3 return func(*args,**kwargs) return inner def w2(func): def inner(*args,**kwargs): # 驗證1 # 驗證2 # 驗證3 return func(*args,**kwargs) return inner @w1 @w2 def f1(arg1,arg2,arg3): print 'f1'
2、生成器
列表生成式(中括號)
優點:使代碼更簡潔,也可以執行函數
list=[ i*2 for i in range(10)] print(list)
運行結果
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
注:range默認是從0開始的。
通過列表生成式,我們可以直接創建一個列表。但是,受到內存限制,列表容量肯定是有限的。而且,創建一個包含100萬個元素的列表,不僅佔用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。
所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環的過程中不斷推算出後續的元素呢?這樣就不必創建完整的list,從而節省大量的空間。在Python中,這種一邊循環一邊計算的機制,稱爲生成器:generator。
要創建一個generator,有很多種方法。第一種方法很簡單,只要把一個列表生成式的[]
改成()
,就創建了一個generator:
l是一個list[],g是一個generator()
generator保存的是算法,每次調用next(g)
,就計算出g
的下一個元素的值,直到計算到最後一個元素,沒有更多的元素時,拋出StopIteration
的錯誤。
#!/usr/bin/env python #-*- coding:utf-8 -*- # Author:DCC l = [x * x for x in range(5)] print(l) g = (x * x for x in range(5)) print(g) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) #運行結果 [0, 1, 4, 9, 16] <generator object <genexpr> at 0x00000000006969E8> 1 9 Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
小結:生成器與列表的區別
生成器:調用的時候纔會生成
列表:先執行出所有的值
用函數製作生成器
斐波拉契數列:
def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return 'done' fib(10) #運行結果 1 3 8 21 55
a, b
=
b, a
+
b
相當於
t
=
(b, a
+
b)
# t是一個tuple
a
=
t[
0
]
b
=
t[
1
]
******yield 將print(b)改爲yield b,fib函數變成generator
def fib(max): n,a,b = 0,0,1 while n < max: #print(b) yield b a,b = b,a+b n += 1 return 'done' print(fib(5)) print(fib(5).__next__()) print(fib(5).__next__()) #運行結果 <generator object fib at 0x000001CDB2D511A8> 1
通過yield實現在單線程的情況下實現併發運算的效果, send的使用
import time def consumer(name): print("%s 準備吃包子啦!" %name) while True: baozi = yield print("包子[%s]來了,被[%s]吃了!" %(baozi,name)) def producer(name): c = consumer('A') c2 = consumer('B') c.__next__() c2.__next__() print("老子開始準備做包子啦!") for i in range(5): time.sleep(1) print("做了2個包子!") c.send(i) c2.send(i) producer("dcc") #運行結果 A 準備吃包子啦! B 準備吃包子啦! 老子開始準備做包子啦! 做了2個包子! 包子[0]來了,被[A]吃了! 包子[0]來了,被[B]吃了! 做了2個包子! 包子[1]來了,被[A]吃了! 包子[1]來了,被[B]吃了! 做了2個包子! 包子[2]來了,被[A]吃了! 包子[2]來了,被[B]吃了! 做了2個包子! 包子[3]來了,被[A]吃了! 包子[3]來了,被[B]吃了! 做了2個包子! 包子[4]來了,被[A]吃了! 包子[4]來了,被[B]吃了!
注:
__next__ 只會調用yield
send不僅會調用yield,野會給yield傳個值
3、迭代器
Iterable:可迭代的
Iterator:迭代器
凡是可作用於for
循環的對象都是Iterable
類型;
凡是可作用於next()
函數的對象都是Iterator
類型,它們表示一個惰性計算的序列;
簡而言之:
1.可用於for循環的
2.有next方法的就可以成爲迭代器
集合數據類型如list
、dict
、str
等是Iterable
但不是Iterator
,不過可以通過iter()
函數獲得一個Iterator
對象。
這些可以直接作用於for
循環的對象統稱爲可迭代對象:Iterable
。
可以使用isinstance()
判斷一個對象是否是Iterable
對象
可以被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator。
>>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance('abc', Iterator) False
生成器都是Iterator
對象,但list
、dict
、str
雖然是Iterable
,卻不是Iterator
。
把list
、dict
、str
等Iterable
變成Iterator
可以使用iter()
函數:
>>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True
實例
#!/usr/bin/env python #-*- coding:utf-8 -*- # Author:DCC import time def timer(func): def deco(*args,**kwargs): # def warpper(*args,**kwargs): start_time = time.time() func(*args,**kwargs) stop_time = time.time() print("the func run time is %s" % (stop_time-start_time) ) return deco @timer # test1 = timer(test1) def test1(): time.sleep(3) print("in the test1") @timer # test2 = timer(test2) =deco def test2(name,age): print(name,age) print("in the test2") test1() test2("dcc","2;5")
4、json的簡單實用
json官方說明參見:http://json.org/
Python操作json的標準api庫參考:http://docs.python.org/library/json.html
重要函數
編碼:把一個Python對象編碼轉換成Json字符串 json.dumps()
解碼:把Json格式字符串解碼轉換成Python對象 json.loads()
>>> import json >>> info = { "name":"test", "age":"25", "sex":"man", "type":{"name1":"test1","parameter":["1","2"]} } >>> print(type(info)) <class 'dict'> >>> j = json.dumps(info) >>> print(j) {"sex": "man", "type": {"name1": "test1", "parameter": ["1", "2"]}, "age": "25", "name": "test"} >>> d = json.loads(j) >>> print(d) {'age': '25', 'type': {'name1': 'test1', 'parameter': ['1', '2']}, 'sex': 'man', 'name': 'test'} >>> print(type(d)) <class 'dict'>
sort_keys(對dict對象進行排序,我們知道默認dict是無序存放的)
#!/usr/bin/env python #-*- coding:utf-8 -*- # Author:DCC import json data1 = {'b':789,'c':456,'a':123} data2 = {'a':123,'b':789,'c':456} d1 = json.dumps(data1,sort_keys=True) d2 = json.dumps(data2) d3 = json.dumps(data2,sort_keys=True) print(d1) print(d2) print(d3) #運行結果 {"a": 123, "b": 789, "c": 456} {"b": 789, "a": 123, "c": 456} {"a": 123, "b": 789, "c": 456}
indent 解碼縮進
#!/usr/bin/env python #-*- coding:utf-8 -*- # Author:DCC data1 = {'b':789,'c':456,'a':123} d1 = json.dumps(data1,sort_keys=True,indent=4) d2 = json.dumps(data1,sort_keys=True) print(d1) print(d2) #運行結果 { "a": 123, "b": 789, "c": 456 } {"a": 123, "b": 789, "c": 456}
用於序列化的兩個模塊
json,用於字符串 和 python數據類型間進行轉換
pickle,用於python特有的類型 和 python的數據類型間進行轉換
Json模塊提供了四個功能:dumps、dump、loads、load
pickle模塊提供了四個功能:dumps、dump、loads、load