Python 第4周 - Python基礎-裝飾器/生成器/迭代器/內置函數/序列化/目錄開發規範

內容html

    1. 裝飾器
    2. 生成器
    3. 迭代器
    4. 內置函數講解
    5. Json and Pickle 數據序列化
    6. 軟件目錄開發規範
    7. 不一樣目錄間的模塊調用
1、裝飾器

 裝飾器:本質就是函數,定義函數器裝飾其餘函數,就是爲其餘函數添加附加功能。python

原則:一、不能修改被裝飾的函數的源代碼
二、不能修改被裝飾的函數的調用方式
實現裝飾器,涉及到的知識量:
  一、函數既「變量」
  二、高階函數
  三、嵌套函數
高階函數+嵌套函數 =》完成裝飾器的使用


一、裝飾器的調用方式:@


二、函數既是「變量」的理解
舉例說明:
python 內部回收的地址說明

三、高階函數
函數返回值

四、嵌套函數
分清,嵌套跟函數內部調用的區別

  五、根據不一樣驗證輸入,走不一樣的驗證方式 算法

裝飾高潮版數據庫

 

2、生成器
 列表生成式能夠直接建立一個列表,做用使代碼更簡潔,數據量大的話,不適合去用,比較受內存的限制。數據量大的話,不只佔用很大的存儲空間,若是整個列表裏面,咱們只須要幾元素,那麼後面元素佔用的空間都浪費了。
舉例:目前有一列表[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錯誤,返回值包含在StopIterationvalue中,要進行異常輸出:

 異常處理,異常捕獲:

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]吃了!
雙向運算 
3、迭代器

一、迭代器定義

注意區分,可迭代對象與迭代器的區別:能夠直接做用於 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循環的數據類型有如下幾種:一類是集合數據類型,如listtupledictsetstr等; 一類是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、listdictstr雖然是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()去判斷;

集合數據類型如listdictstr等是Iterable但不是Iterator,不過能夠經過iter()函數得到一個Iterator對象。

4、內置函數

 內置函數

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

5、Json and Pickle 數據序列化

 一、序列化與反序列化的做用:

有兩種方式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 都是平臺通用。

A、第一步、pickle 序列化
    pickle 字典序列化 Pickle.dump操做,dumps()函數執行和dump() 函數相同的序列化。取代接受流對象並將序列化後的數據保存到磁盤文件,這個函數簡單的返回序列化的數據。
# 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(XnumberqX 400-100-119qXworkqXITqXnameqX chenchangqingqu. 

 

C、第三步、pickle 反序列化

     pickle 字典反序列化 Pickle.load loads()函數執行和load() 函數同樣的反序列化。取代接受一個流對象並去文件讀取序列化後的數據,它接受包含序列化後的數據的str對象, 直接返回的對象。
#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 序列化,以下

 

6、軟件目錄開發規範

 爲何要設計好目錄結構?

設計一個層次清晰的目錄結構,就是爲了達到如下兩點:

  • 可讀性高: 不熟悉這個項目的代碼的人,一眼就能看懂目錄結構,知道程序啓動腳本是哪一個,測試目錄在哪兒,配置文件在哪兒等等。從而很是快速的瞭解這個項目。
  • 可維護性高: 定義好組織規則後,維護者就能很明確地知道,新增的哪一個文件和代碼應該放在什麼目錄之下。這個好處是,隨着時間的推移,代碼/配置的規模增長,項目結構不會混亂,仍然可以組織良好。

目錄組織方式
Foo/
|-- bin/
| |-- foo
|
|-- foo/
| |-- tests/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- docs/
| |-- conf.py
| |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README

解析一下:

  1. bin/: 存放項目的一些可執行文件,固然你能夠起名script/之類的也行。
  2. foo/: 存放項目的全部源代碼。(1) 源代碼中的全部模塊、包都應該放在此目錄。不要置於頂層目錄。(2) 其子目錄tests/存放單元測試代碼; (3) 程序的入口最好命名爲main.py。
  3. docs/: 存放一些文檔。
  4. setup.py: 安裝、部署、打包的腳本。
  5. requirements.txt: 存放軟件依賴的外部Python包列表。
  6. README: 項目說明文件。

這裏重點解析關於README的內容
它須要說明如下幾個事項:

  1. 軟件定位,軟件的基本功能。
  2. 運行代碼的方法: 安裝環境、啓動命令等。
  3. 簡要的使用說明。
  4. 代碼目錄結構說明,更詳細點能夠說明軟件的基本原理。
  5. 常見問題說明。
7、不一樣目錄間的模塊調用

 不一樣目錄間的模塊調用。使用 from  ..  import .. 的模式導入

以上利用系統的環境變量,找到相對路徑BASE_DIR ,使用from 導入模塊。

8、做業

做業需求:

模擬實現一個ATM + 購物商城程序

  1. 額度 15000或自定義
  2. 實現購物商城,買東西加入 購物車,調用信用卡接口結帳
  3. 能夠提現,手續費5%
  4. 支持多帳戶登陸
  5. 支持帳戶間轉帳
  6. 記錄每個月平常消費流水
  7. 提供還款接口
  8. ATM記錄操做日誌 
  9. 提供管理接口,包括添加帳戶、用戶額度,凍結帳戶等。。。
  10. 用戶認證用裝飾器

做業規劃:

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
做業示例

 做業講解

相關文章
相關標籤/搜索