內容html
裝飾器:本質就是函數,定義函數器裝飾其餘函數,就是爲其餘函數添加附加功能。python
原則:一、不能修改被裝飾的函數的源代碼
二、不能修改被裝飾的函數的調用方式
實現裝飾器,涉及到的知識量:
一、函數既「變量」
二、高階函數
三、嵌套函數
高階函數+嵌套函數 =》完成裝飾器的使用
一、裝飾器的調用方式:@
![](http://static.javashuo.com/static/loading.gif)
二、函數既是「變量」的理解
舉例說明:
python 內部回收的地址說明
三、高階函數
函數返回值
四、嵌套函數
分清,嵌套跟函數內部調用的區別
五、根據不一樣驗證輸入,走不一樣的驗證方式 算法
裝飾高潮版數據庫
列表生成式:能夠直接建立一個列表,做用使代碼更簡潔,數據量大的話,不適合去用,比較受內存的限制。數據量大的話,不只佔用很大的存儲空間,若是整個列表裏面,咱們只須要幾元素,那麼後面元素佔用的空間都浪費了。
舉例:目前有一列表[0,1,2,3,4,5,6,7,8,9],須要在每一個元素上加1,看實現的方法
第一種方法: >>> a = [0,1,2,3,4,5,6,7,8,9] >>> b = [] >>> for i in a:b.append(i+1) #定義b的空列表,把a的值加1後賦給b ... >>> print (b) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> a = b >>>print (a) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 第二種方法: >>> a = [0,1,2,3,4,5,6,7,8,9] >>> for index,i in enumerate(a): ... a[index] += 1 #利用索引的切片取值,在循環加1,打印 ... >>> print (a) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 第三種方法: >>> a = [0,1,2,3,4,5,6,7,8,9] >>> b = [i+1 for i in a] >>> print (b) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
生成器(generator):列表生成式,是把列表裏面的全部元素完整的進行打印。生成器就是這種沒必要建立完整的list,從而節 省大量的內存空間。在python環境中,這種一邊循環一邊計算的機制就成稱之爲生成器。
一、簡單的生成器建立,只須要把列表生成式的[]換成(), 就建立完成:
1 列表生成式: 2 >>> a = [ i*2 for i in range(10) ] 3 >>> print (a) 4 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 5 備註:做用使代碼更簡潔,數據量大的話,不適合去用,比較耗空間 8 =============================== 9 生成器: 10 >>> b = ( i*2 for i in range(10) ) 11 >>> print (b) 12 <generator object <genexpr> at 0x1021e0938> 13 >>> b.__next__() 14 0 15 >>> b.__next__() 16 2 17 >>> b.__next__() 18 4 備註:只有調用時纔會生成相應的數據;只記錄當前的位置,並且方法只有一個__next__(),不能返回去取用,(python 2.7版本是 next()),直到把數值取完爲止。數據取完以後,進行往下取數值,就會報錯。
不斷的使用__next()__,取數值,比較麻煩,能夠結合for的循環使用,由於生成器能夠是迭代的對象:編程
觀察如下,兩個的變化:json
打印了內存的地址: >>> d = ( i +1 for i in range(10)) >>> for i in d: ... print (d) ... <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> 打印輸出內容: >>> d = ( i +1 for i in range(10)) >>> for i in d: ... print (i) ... 1 2 3 4 5 6 7 8 9 10
因此,建立了一個生成器,基本上永遠不會調用__,而是經過循環來迭代它,而且不須要關心的錯誤。next()__forStopIteration
二、利用函數進行算法推算,並改爲生成器的形式數組
若有推算的算法比較複雜,用相似的列表生成式的for 循環沒法實現的時候,還能夠用函數來實現。併發
以下:除第一個數,第二個數外。任意一個數均可以由前兩個數相加獲得:app
a = [1,1,2,3,5,8,13,21,34,55.......]ssh
要計算得出以上的數學列表,單獨使用列表生成式,很難實現。用函數進行打印:
def fib(max): n,a,b = 0,0,1 while n < max: print(b) # 還不是生成器,目前的執行輸出仍是所有打印,數據量大會卡死 a, b = b, a+b #注意賦值的寫法,其中左邊"a"的值等於右邊"b"的值,左邊 」b「的值等於右邊「a+b」的值。 n = n + 1 return 'done' f=fib(10)
print(f) 輸出: 1 1 2 3 5 8 13 21 34 55
done
以上函數實現了數列的推算,但種邏輯還不是生成器的寫法,如下把print(b)改成yield b就能夠實現。以下:
def fib(max): n,a,b = 0,0,1 while n < max: #print(b) yield b a, b = b, a+b # n = n + 1 return 'done' f = fib(10) print(f) 輸出: <generator object fib at 0x102180888> 打印出生成器的內存地址。
注意:以上是生成器的另一種定義的方式,若是一個函數的定義中包含yield關鍵字,那麼這個函數不是再是普通的函數,而是一個生成器函數。
三、生成器和函數的執行流程
重點理解:生成器和函數的執行流程不同。函數是順序執行,遇到return 語句或者最後一句函數語句就返回。而變成生成器的函數,在每次調用__next__ 的時候執行,遇到yield語句返回,再次執行時會從上次返回的yield語句處繼續執行。函數測試最好加入斷點的方法驗證。
對比,如下兩個斷點判斷執行的例子,觀察執行順序:
A、使print(b) 打印
def fib(max): #第二步,函數體處理過程 n,a,b = 0,0,1 #第三步 while n < max: #第四步,執行while循環,直到計算10次,完成整個循環退出。 print(b) #yield b a, b = b, a+b n = n + 1 return 'done' f = fib(10) #熟悉調用函數體 ,第一步 print(f) #第五步,調用打印 print("來個斷點判斷") print(f) #第六步,只會打印函數的return返回值,並不執行while 循環。
輸出:
1
1
2
3
5
8
13
21
34
55
done
來個斷點
done
B、使yield來打印
def fib(max): n,a,b = 0,0,1 while n < max: yield b a, b = b, a+b n = n + 1 return 'done' f = fib(10) #f:<generator object fib at 0x1020808e0> print(f.__next__()) #第一步,執行輸出,調用函數進行計算,第一次執行完以後跳出,執行第二print的輸出 print(f.__next__()) #第二步,執行輸出,接上個print 執行後,調用函數進行計算,往下繼續計算,不重複。 print("來個斷點") #第三步,加個隔斷 print(f.__next__()) #第四步,接着後面沒有打印數值,進行傳參,進行打印 print("來個斷點2") print(f.__next__()) 輸出:
1
來個斷點1
1
2
來個斷點2
3
在循環過程當中不斷調用yield
,就會不斷中斷。固然要給循環設置一個條件來退出循環,否則就會產生一個無限數列出來。
C、使用for循環來迭代,進行對生成器的取值:
把函數變成生成器,基本上不會使用__next()__來獲取下一個返回值,都是經過for循環取值
def fib(max): n,a,b = 0,0,1 while n < max: yield b a, b = b, a+b n = n + 1 return 'done' f = fib(10) for i in (f): print (i) 輸出: 1 1 2 3 5 8 13 21 34 55
備註:使用for
循環調用生成器時,拿不到生成器的return
語句的返回值。若是想要拿到返回值,必須捕獲StopIteration
錯誤,返回值包含在StopIteration
的value
中,要進行異常輸出:
異常處理,異常捕獲:
def fib(max): n,a,b = 0,0,1 while n < max: yield b a, b = b, a+b n = n + 1 return 'done' f = fib(10) for i in (f): while True: try: x = next(f) print('f:',x) except StopIteration as e: print('Generator return value:', e.value) break 輸出: f: 1 f: 2 f: 3 f: 5 f: 8 f: 13 f: 21 f: 34 f: 55 Generator return value: done
D、yield實如今單線程的狀況下實現併發運算的效果
以下:
1 import time 2 def consumer(name): 3 print("%s 準備吃包子啦!" % name) 4 while True: 5 baozi = yield #定義生成器位置 6 7 print("包子[%s]來了,被[%s]吃了!" %(baozi,name)) 8 9 10 def producer(name): 11 c = consumer('A') 12 c2 = consumer('B') 13 print(dir(c)) 14 c.__next__() 15 c2.__next__() 16 print("老子開始準備作包子啦!") 17 for i in range(5): 18 time.sleep(1) 19 c.send(i) #可使用dir(c),查看生成器的調用方式 20 c2.send(i) #send跟baozi = yield是什麼關係 21 22 producer("chen1203") 23 輸出: 24 ['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw'] 25 A 準備吃包子啦! 26 B 準備吃包子啦! 27 老子開始準備作包子啦! 28 包子[0]來了,被[A]吃了! 29 包子[0]來了,被[B]吃了! 30 包子[1]來了,被[A]吃了! 31 包子[1]來了,被[B]吃了! 32 包子[2]來了,被[A]吃了! 33 包子[2]來了,被[B]吃了! 34 包子[3]來了,被[A]吃了! 35 包子[3]來了,被[B]吃了! 36 包子[4]來了,被[A]吃了! 37 包子[4]來了,被[B]吃了!
一、迭代器定義
注意區分,可迭代對象與迭代器的區別:能夠直接做用於 for
語句進行循環的對象稱之爲可迭代對象;能夠被next()
函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator
。生成器必定是迭代器,但迭代器不必定是生成器。
a = [1,2] for i in a: print (i) 輸出: 1 2 b = {"a":123,"b":456} for i in b: print(i) 輸出: a b
由上可述,能夠直接做用於for
循環的數據類型有如下幾種:一類是集合數據類型,如list
、tuple
、dict
、set
、str
等; 一類是generator
,包括生成器和帶yield
的generator function。能夠直接做用於 for
語句進行循環的對象稱之爲可迭代對象。
內置的數據類型(列表、元組、字符串、字典等)能夠經過 for
語句進行迭代,咱們也能夠本身建立一個容器,包含一系列元素,能夠經過 for
語句依次循環取出每個元素,這種容器就是 迭代器(iterator)。
建立迭代器對象的好處是當序列長度很大時,能夠減小內存消耗,由於每次只須要記錄一個值即刻。
二、使用isinstance()
判斷一個對象是不是迭代(Iterable)
對象:
>>> from collections import Iterable #導入Iterable(可迭代對象模塊) >>> isinstance([],Iterable) True >>> isinstance((),Iterable) True >>> a = "abc" >>> isinstance("abc",Iterable) True >>> isinstance('b',Iterable) True >>> isinstance(100,Iterable) False
>>> isinstance((x for x in range(3)),Iterable)
True
使用isinstance()
判斷一個對象是不是迭代器:
from collections import Iterator print (isinstance([],Iterator)) print (isinstance((),Iterator)) print (isinstance((x for x in range(3)),Iterator)) 輸出: False False True
總結:由上得出,生成器、列表、元組、字符串都是可迭代對象,生成器必定是迭代器。數字是非可迭代對象。
三、除了用for遍歷,迭代器還能夠經過next()方法逐一讀取下一個元素。要建立迭代器有3種方法,其中前兩種分別是:
A、list
、dict
、str
雖然是Iterable(可迭代對象)
,卻不是Iterator(迭代器)。但
內置函數 iter()
將可迭代對象轉化爲迭代器
列表迭代器
ita = iter([1,2,3,4]) print(type(ita)) #列表迭代器 print(next(ita)) print(next(ita)) print(next(ita)) 輸出: <class 'list_iterator'> 1 2 3 逐一取值。注:把ita = iter([1,2,3,4])改成ita = iter((1,2,3,4)),則爲元組迭代器。
B、 爲容器對象添加 __iter__()
和 __next__()
方法(Python 2.7 中是 next()
);__iter__()
返回迭代器對象自己 self
,__next__()
則返回每次調用 next()
或迭代時的元素;
class Container: def __init__(self, start = 0, end = 0): self.start = start self.end = end def __iter__(self): print("[LOG] I made this iterator!") return self def __next__(self): print("[LOG] Calling __next__ method!") if self.start < self.end: i = self.start self.start += 1 return i else: raise StopIteration() c = Container(0, 3) for i in c: print(i) 輸出: [LOG] I made this iterator! [LOG] Calling __next__ method! 0 [LOG] Calling __next__ method! 1 [LOG] Calling __next__ method! 2 [LOG] Calling __next__ method!
總結:
凡是可做用於for
循環的對象都是Iterable
類型;
凡是可做用於next()
函數的對象都是Iterator
類型,它們表示一個惰性計算的序列(惰性計算,就是計算到的時候纔打印出來,沒計算到距不打印),查看迭代類型是否可使用next(),使用dir()去判斷;
集合數據類型如list
、dict
、str
等是Iterable
但不是Iterator
,不過能夠經過iter()
函數得到一個Iterator
對象。
內置函數
abs()#絕對值 all()#只要一個爲假,都是假 any()#只要一個爲真,都是真 ascii()#把一個內存形式打印成字符串的格式 bin()#一個整數,十進制轉二進制 bool()#布爾值,判斷真假 bytearray() bytes() callable()#判斷可調用的信息 chr()#利用數字打印asscii碼 ord()#利用asscii碼取對應的數字 compile()#用於底層,把代碼進行編譯的工具 complex() dict()#字典 dir()#查使用方法 divmod()#相除,返回餘數 enumerate() eval() exec() filter()#一組數據裏面,過濾你想要的數值,打印出來 如: res = filter(lambda n:n>5,range(10)) for i in res: print (i) map()#把後面的值放給前面出來,並把結果打印 res = map(lambda n:n*n,range(10)) for i in res: print (i) reduce()#2.7版本仍是能夠直接調用,3版本之後都是放在模塊裏面了 import functools res = functools.reduce(lambda x,y:x+y,range(10)) print (res) frozenset()#凍結,不可變的集合 globals()#返回當前整個程序裏面全部變量的key/values模式 hash()#中文名散列,處理過程,須要找到一個固定的映射關係,經過遞歸的二分查找進行劃分歸類查找。 hex()#把一個數字轉成16進制 locals()#用於函數內部本地打印 object()#對象,用類的時候使用。一個個體,就是對象。每一個對象都有屬於本身的屬性。 oct()#八進制,逢8進1 pow()#多少次方 repr()#與ascii()一致 reversed()#反轉 round()# round(1.222,2) 保留兩位小數點 slice()#切片 如:d=range(10) t = d[slice(2,5)] sorted() #把字典排序,按key或values 來排序 如: a = {6:2,9:0,3:4,6:5,10:7,11:22} print (sorted(a.items())) 輸出: [(3, 4), (6, 5), (9, 0), (10, 7), (11, 22)] print (sorted(a.items(),key = lambda n:n[1])) 輸出: [(9, 0), (3, 4), (6, 5), (10, 7), (11, 22)] zip()#拉鍊式組合 如: a = [1,2,3,4] b = ["a","b","c","d"] for i in zip(a,b): print (i) 輸出: (1, 'a') (2, 'b') (3, 'c') (4, 'd') __import__() #模塊導入, 如:__import__("chen1203") 其餘常見的內置函數不列舉
對應函數的官網連接:https://docs.python.org/3/library/functions.html?highlight=built#ascii
一、序列化與反序列化的做用:
有兩種方式json和pickle:json適合用其餘的平臺,pickle只能在python中應用。pickle 與json 模塊一般是將python對象序列化爲二進制流或文件,計算機底層是跟的二進制進行交互的。幾
能夠被序列化的類型有:
* None,True 和 False;
* 整數,浮點數,複數;
* 字符串,字節流,字節數組;
* 包含可pickle對象的tuples,lists,sets和dictionaries;
* 定義在module頂層的函數:
* 定義在module頂層的內置函數;
* 定義在module頂層的類;
* 擁有__dict__()或__setstate__()的自定義類型;
注意:對於函數或類的序列化是以名字來識別的,因此須要import相應的module。
序列化與反序列化,就是在內存之間進行數據翻譯。pickle與json的功能效果差很少。但json並不徹底能序列化,因此出現python專用的pickle,pickle 只能在python中使用。
二、json 序列化與反序列化
A、第一步:經過序列化,把info信息從內存寫到文件中底
#json 序列化 import json info = { "name": "chenchangqing", "work":"IT", "number":"400-100-119" } f = open("test.txt","w+") f.write(json.dumps(info)) #把info信息序列化 f.close()
B、第二步,查看test.txt 文件
#test.txt 文件內容的存儲信息 {"number": "400-100-119", "work": "IT", "name": "chenchangqing"}
C、第三步、json 反序列化
#json 反序列化 import json file = open("test.txt","r") data = json.load(file)#經過使用json.load對文件信息反序列化出來。 print (data) file.close()
三、pickle 序列化與反序列化
pickle 是python通用的包括類、字典、對象、列表均可以序列化,json \ xml 都是平臺通用。
# pickle 序列化語法 import pickle info = { "name": "chenchangqing", "work": "IT", "number": "400-100-119" } f = open("test_pickle.txt", "wb") #因爲pickle是使用二進制,因此使用wb f.write(pickle.dumps(info)) f.close()
B、第二步、查看test_pickle 文件
#文件內容�}q(XnumberqX400-100-119qXworkqXITqXnameqX chenchangqingqu.
C、第三步、pickle 反序列化
#pikcel 反序列化 import pickle file = open("test_pickle.txt","rb") data = pickle.load(file) print (data) file.close() 輸出: {'work': 'IT', 'name': 'chenchangqing', 'number': '400-100-119'}
總結:pickle 序列化,以下
爲何要設計好目錄結構?
設計一個層次清晰的目錄結構,就是爲了達到如下兩點:
目錄組織方式
Foo/
|-- bin/
| |-- foo
|
|-- foo/
| |-- tests/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- docs/
| |-- conf.py
| |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README
解析一下:
這裏重點解析關於README的內容
它須要說明如下幾個事項:
不一樣目錄間的模塊調用。使用 from .. import .. 的模式導入
以上利用系統的環境變量,找到相對路徑BASE_DIR ,使用from 導入模塊。
做業需求:
模擬實現一個ATM + 購物商城程序
做業規劃:
shopping.py buy 調用信用卡接口 直接扣款 ATM.py 提款 還款 查餘額 查帳單 1 2 3 4 5 容許多個帳號登陸 容許帳號之間的登陸 提供還款接口 記錄操做日誌 提供管理接口,包括添加帳戶、用戶額度,凍結帳戶等 用戶認證用裝飾器
實現ATM經常使用功能 功能所有用python的基礎知識實現,用到了time\os\sys\json\open\logging\函數\模塊知識, 主要幫給你們一個簡單的模塊化編程的示例 注意:只實現了"還款"和"取現功能" 程序結構: day5-atm/ ├── README ├── atm #ATM主程目錄 │ ├── __init__.py │ ├── bin #ATM 執行文件 目錄 │ │ ├── __init__.py │ │ ├── atm.py #ATM 執行程序 │ │ └── manage.py #ATM 管理端,未實現 │ ├── conf #配置文件 │ │ ├── __init__.py │ │ └── settings.py │ ├── core #主要程序邏輯都 在這個目錄 裏 │ │ ├── __init__.py │ │ ├── accounts.py #用於從文件里加載和存儲帳戶數據 │ │ ├── auth.py #用戶認證模塊 │ │ ├── db_handler.py #數據庫鏈接引擎 │ │ ├── logger.py #日誌記錄模塊 │ │ ├── main.py #主邏輯交互程序 │ │ └── transaction.py #記帳\還錢\取錢等全部的與帳戶金額相關的操做都 在這 │ ├── db #用戶數據存儲的地方 │ │ ├── __init__.py │ │ ├── account_sample.py #生成一個初始的帳戶數據 ,把這個數據 存成一個 以這個帳戶id爲文件名的文件,放在accounts目錄 就好了,程序本身去會這裏找 │ │ └── accounts #存各個用戶的帳戶數據 ,一個用戶一個文件 │ │ └── 1234.json #一個用戶帳戶示例文件 │ └── log #日誌目錄 │ ├── __init__.py │ ├── access.log #用戶訪問和操做的相關日誌 │ └── transactions.log #全部的交易日誌 └── shopping_mall #電子商城程序,需單獨實現 └── __init__.py
做業講解