本節內容html
1.迭代器 & 生成器python
2.裝飾器mysql
3.Json & pickle 數據序列化nginx
4.軟件目錄結構規範git
1、列表生成式, 迭代器 & 生成器github
列表生成式redis
首先, 看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 如今讓列表裏面的每一個值都加1, 如何實現?算法
a = [0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9] b = [] for i in a:b.append(i+1) a = b >>>>>>>>a的結果: [1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10]
a = [0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9] for index,i in enumerate(a): a[index]+=1 >>>>>>a 的結果爲: [1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10]
a = [0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9] a = map(lambda x:x+1, a) print(a) for i in a: print(i) >>>>>>輸出: <map object at 0x0000021EA94291D0> 1 2 3 4 5 6 7 8 8 9 10
還有種寫法以下:sql
a = [i + 1 for i in range (10)] print(a) >>>>>>輸出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
上面的例子就叫作列表生成.json
生成器
經過列表生成式,就能夠直接建立一個列表。可是,受到內存限制,列表容量確定是有限的。並且,建立一個包含100萬個元素的列表,不只佔用很大的內存存儲空間,若是咱們僅僅須要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。
因此,若是列表元素能夠按照某種算法推算出來,那咱們是否能夠在循環的過程當中不斷推算出後續的元素呢?這樣就沒必要建立完整的list,從而節省大量的空間。在Python中,這種一邊循環一邊計算的機制,稱爲生成器(generator)。
要建立一個generator,有不少種方法。第一種方法很簡單,只要把一個列表生成式的[]
改爲()
,就建立了一個generator:
a = [i + 1 for i in range (10)] >>>>>>>>>> b = (i + 1 for i in range (10)) print(b) >>>>>>>>>>輸出結果爲: <generator object <genexpr> at 0x0000028FFC57FFC0>
建立a, b的區別僅在於最外層的[] 和(), a是一個list,b是一個generator.
能夠直接打印出list a的元素, 那如何打印出生成器generator b裏面的元素呢?
若是想要一個個打印出來的話, 能夠經過帶哦用next()函數來獲取下一個返回值:
>>> a = (x * x for x in range(10)) >>> next(a) 0 >>> next(a) 1 >>> next(a) 4 >>> next(a) 9 >>> next(a) 16 >>> next(a) 25 >>> next(a) 36 >>> next(a) 49 >>> next(a) 64 >>> next(a) 81 >>> next(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
generator保存的實際上是算法,每次的調用next(a), 就計算出a的下一個值, 知道計算到最後一個元素, 沒有更多的元素時, 拋出StopIteration的報錯。
固然, 如上的不斷調用實在是太尷尬了, 正確的方法是使用for循環,由於generator也是可迭代對象:
>>> a = (x * x for x in range(10)) >>> for i in a: ... print(i) ... 0 1 4 9 16 25 36 49 64 81
建立一個生成器後, 通常不會調用next, 而是用for循環來迭代它, 而且不須要關心StopIteration
的錯誤。
generator很是強大。若是推算的算法比較複雜,用相似列表生成式的for
循環沒法實現的時候,還能夠用函數來實現。
好比,著名的斐波拉契數列,除了第一個和第二個數外,任意一個數都是前2個數的和:
1, 1, 2, 3, 5, 8, 13, 21, 34, ......
斐波拉契數列用列表生成式寫不出來, 可是用函數是能夠解決的:
def fib(max): n, a, b = 0, 0, 1 while n < max : print(b) a, b = b, a + b n += 1 return 'done' fib(10) >>>>>>> 1 1 2 3 5 8 13 21 34 55
注意上面的 a, b = b, a + b
並非想象中的:
a = b b = a+b
而是至關於:
t = (b, a + b)# t是一個tuple a = t[0] b = t[1]
但沒必要顯示的寫出臨時變量t就能夠賦值。
能夠看出, fib函數其實是定義了斐波拉契的推算規則, 從而獲得後續元素, 跟generator的邏輯很類似。
其實上面的函數跟generator僅一步之遙。只須要把print(b)改爲yield(b)就能夠轉化了。
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n +=1 return 'done' f = fib(5) print(f)
輸出結果:<generator object fib at 0x01D87180>
generator跟函數的運行流程不同。韓式是順序執行,遇到return語句或者最後一行函數語句就返回。而變成生成器後經過next()調用,遇到yield語句返回,再次執行從上次返回的yield語句繼續執行。
f = fib(5) print(f) print(f.__next__()) print(f.__next__()) print("作點其餘的事") print(f.__next__()) print(f.__next__()) <generator object fib at 0x00A27180> 1 1 作點其餘的事 2 3
在上面的fib的例子中,咱們在循環過程當中不斷調用yield,就會不斷中斷。固然要給循環設計一個退出條件,否則會產生一個無限數列。
其實,一樣的, 函數改成generator後,咱們也能夠用for循環來迭代而不是next調用。
f = fib(5) for i in f: print(i) 1 1 2 3 5
調用for循環後,會發現沒法獲得函數返回值,若是想拿到它,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中:
f = fib(5) while True: try: x = next(f) print('F:',x) except StopIteration as e: print("Generator return value:", e.value) break 結果: F: 1 F: 1 F: 2 F: 3 F: 5 Generator return value: done
還可經過yield實如今單線程的狀況下實現併發運算的效果
#!/user/bin/env python # -*- coding: utf-8 -*- import time def consumer(name): print("%s準備吃包子啦!" % name) while True: baozi = yield print("包子[%s]來了,被[%s]吃了!"%(baozi, name)) def producer(): c1 = consumer('Dandy') c2 = consumer('Claire') c1.__next__() c2.__next__() print(' 師傅開始準備作包子啦!') for i in range(10): time.sleep(1) print('作了一個包子,分2半。') c1.send(i) c2.send(i) producer()
Dandy準備吃包子啦! Claire準備吃包子啦! 師傅開始準備作包子啦! 作了一個包子,分2半。 包子[0]來了,被[Dandy]吃了! 包子[0]來了,被[Claire]吃了! 作了一個包子,分2半。 包子[1]來了,被[Dandy]吃了! 包子[1]來了,被[Claire]吃了! 作了一個包子,分2半。 包子[2]來了,被[Dandy]吃了! 包子[2]來了,被[Claire]吃了! 作了一個包子,分2半。 包子[3]來了,被[Dandy]吃了! 包子[3]來了,被[Claire]吃了!
迭代器
咱們已經知道,能夠直接做用於for銷魂還得額數據類型有如下幾種:一類是集合數據類型,入list, list, dict, set, str等。另外一類是generator, 包括生成器和帶yield的generator function。
上述能夠直接做用於for循環的對象,統一稱爲可迭代對象:Iterable。
能夠用isinstance()判斷一個對象是不是Iterable對象。
>>> from collections import Iterable >>> isinstance([],Iterable) True >>> isinstance({},Iterable) True >>> isinstance('abc',Iterable) True >>> isinstance((x for x in range(10)),Iterable) True >>> isinstance(100,Iterable) False
生成器都是Iterator對象,可是list,dict,str雖然是Iterable,但卻不是Iterator。
把list,dict,str等Iterable變成Iterator能夠用iter()函數:
>>> isinstance(iter([]),Iterator) True >>> isinstance(iter('abc'),Iterator) True >>>
你可能會困惑,爲何list,dict,str等不是Iterator?
這是由於python的Iterator對象表示的是一個數據流,Iterator對象能夠被next()函數調用並不斷返回下一個數據,直到沒有數據拋出StopIteration。能夠把這個數據流當作是一個有序的序列,
但咱們卻不能提早知道序列的長度,只能不斷的經過next()的調用實現計算出下一個數,因此Iterator的計算是惰性的,自由在須要返回下一個數據時纔會計算。
Iterator甚至能夠表示一個無限大的數據流,可是list等卻永遠不可能存儲總體的天然數。
小結
凡是可做用於for循環的對象都是Iterable類型(可迭代對象);
凡是可做用於next()函數的對象都是Iterator類型,它表示一個惰性計算的序列;
集合數據類型例如 list,dict,str等都是Iterable但不是Iterator,不過能夠經過iter()函數得到一個Iterator對象。
Python 的for循環其實本質上能夠說,就是一個不斷的調用next()函數的過程,例如
for x in [1, 2, 3, 4]: pass
徹底等價於:
# 首先得到Iterator對象 it = iter([1, 2, 3, 4]) #循環 while True: try: #獲取下一個值: x = next(it) except StopIteration: #遇到StopIteration就退出循環 break
2、裝飾器
模擬一種狀況,假如如今你手上的網站如今有如下幾個模塊
def home(): print("---首頁----") def america(): print("----歐美專區----") def japan(): print("----日韓專區----") def dalu(): print("----大陸專區----")
如今須要對這幾個受歡迎的版塊進行改版,好比大陸跟日韓專區須要收費,拿到這個需求後,先要讓其進行用戶認證,認證經過後再盤點是否是VIP,付費會員就能夠觀看。需求其實很簡單,由於須要對多個板塊進行認證,就須要寫一個獨立而且通用的模塊,而後每一個版塊調用它。
#!/user/bin/env python # -*- coding: utf-8 -*- user_status = False def login(): _username = 'dandy' # 僞裝是DB抓取的用戶信息 _password = 'password.1' global user_status if user_status == False: username = input("user:") password = input("password:") if username == _username and password == _password: print("Welcome login...") user_status = True else: print("Wrong username or password !") else: print("用戶已登錄,驗證經過...") def home(): print("---首頁----") def america(): print("----歐美專區----") def japan(): login()#驗證 print("----日韓專區----") def dalu(): login()#驗證 print("----大陸專區----")
這時候你可能信心滿滿的去提交審覈,沒想到幾分鐘就被打回來。雖然代碼是實現了功能,可是須要加認證在各個模塊代碼,這直接違反了軟件開發的一個原則「開放-封閉」,簡單來講,就是規定了已經實現的功能代碼不容許被修改,但能夠擴展,即:
· 封閉:已實現的功能代碼
· 開放:對擴展開放
這時候咱們能夠利用高階函數,把一個函數看成一個參數傳給另一個函數。這樣只須要寫一個認證方法,每次調用須要驗證的時候直接把功能的函數名看成參數傳給須要驗證的模塊,就能夠實現功能了。
1 #!/user/bin/env python 2 # -*- coding: utf-8 -*- 3 4 user_status = False 5 6 7 def login(func): 8 _username = 'dandy' # 僞裝是DB抓取的用戶信息 9 _password = 'password.1' 10 global user_status 11 12 if user_status == False: 13 username = input("user:") 14 password = input("password:") 15 16 if username == _username and password == _password: 17 print("Welcome login...") 18 user_status = True 19 else: 20 print("Wrong username or password !") 21 22 if user_status == True: 23 func()#只要驗證經過就會調用相應的功能模塊 24 25 26 def home(): 27 print("---首頁----") 28 29 30 def america(): 31 print("----歐美專區----") 32 33 34 def japan(): 35 # login()#驗證 36 print("----日韓專區----") 37 38 39 def dalu(): 40 # login()#驗證 41 print("----大陸專區----") 42 43 home() 44 login(america) 45 login(dalu)
很開心,美滋滋。終於實現了老闆的要求,不改變原功能代碼的前提下,給功能加上驗證。可是這時候經理看到後發現你又犯了大忌,什麼大忌?
改變了調用方式!如今全部須要認證的模塊都須要從新調用你的login()方法並把本身的函數名傳給你,別人以前可不是這麼調用的,若是有100個模塊這樣調用是否是100個模塊都要更改調用方式,可能模塊跟方法是分開封裝的,怎麼去找那些模塊呢?
如今讓咱們提起來一個學過的知識:匿名函數(lambda)
def plus(n): return n+2 plus2 = lambda x:x+2
上面的2種寫法是否是表明一樣的意思?
給 lambda x:x+2 取了個名字叫plus2 , 是否是至關於def plus2(x)
給函數賦值變量名就像def func_name 是同樣的效果,以下面的plus(n)函數,你調用時能夠用plus名,還能夠再起個其餘名字,如
calc = plus calc(n)
以前的驗證登錄的代碼:
home() login(japan) login(dalu)
之因此改變了調用方式,是由於用戶每次調用時須要執行login(參數), 能夠稍微改一下。
home() japan= login(japan) dalu = login(dalu)
這樣調用dalu的時候,其實至關於調用了login(dalu),經過login裏面的驗證後自動調用dalu的功能。
那就應該這樣寫
home() japan= login(japan)#這裏其實替換了japan函數 dalu= login(dalu) #那用戶調用時依然寫 japan()
可是,問題在於內部已經有func(), japan= login(japan) 還沒等用戶調用,你就會內部執行這句的時候顯把america執行了。應該是用戶調用的時候再調用啊?
這裏咱們又能夠用到嵌套函數,想實現一開始寫 japan= login(japan) 不觸發你函數的執行只須要在login裏面再定義一層函數,第一次調用 japan= login(japan)值調用到外層的login,這個login雖然會執行可是不會觸發認證,由於認證的全部的代碼都被封裝在login裏層的新定義的函數裏, login只返回了裏層的函數名,這樣再執行japan()時,就會調用裏層的函數。
可能你們也有點暈了,直接上代碼:
def login(func): # 把要執行的模塊從這裏傳進來 def inner(): # 再定義一層函數 _username = 'dandy' # 僞裝是DB抓取的用戶信息 _password = 'password.1' global user_status if user_status == False: username = input("user:") password = input("password:") if username == _username and password == _password: print("Welcome login...") user_status = True else: print("Wrong username or password !") if user_status == True: func() # 只要驗證經過就會調用相應的功能模塊 return inner # 用戶調用login的時候就會返回inner的內存地址,下次調用加上()纔會執行inner函數
按照python對於裝飾器的定義,咱們這時候能夠把這個代碼去掉:
japan= login(japan) #你在這裏至關於把japan這個函數替換了
只須要在須要裝飾的函數上面加上下面的代碼:
def home(): print("---首頁----") def america(): print("----歐美專區----") @login def japan(): # login()#驗證 print("----日韓專區----") @login def dalu(): # login()#驗證 print("----大陸專區----")
效果同樣。太棒了。
你開心的看着這一串代碼,忽然又想試試能不能傳參給版塊:
@login def japan(): # login()#驗證 print("----日韓專區----") japan("3p")
結果發現報錯了。難道這個裝飾器不能傳參數麼?
固然!若是不能傳參數,還介紹了幹嗎
def login(func): # 把要執行的模塊從這裏傳進來 def inner(arg1): # 再定義一層函數 _username = 'dandy' # 僞裝是DB抓取的用戶信息 _password = 'password.1' global user_status if user_status == False: username = input("user:") password = input("password:") if username == _username and password == _password: print("Welcome login...") user_status = True else: print("Wrong username or password !") if user_status == True: func(arg1) # 只要驗證經過就會調用相應的功能模塊 return inner # 用戶調用login的時候就會返回inner的內存地址,下次調用加上()纔會執行inner函數
咱們給inner函數加了個arg1參數func的地方也加了個arg1,這樣調用會傳到相應的版塊。
再試一次呢?
def login(func): # 把要執行的模塊從這裏傳進來 def inner(arg1): # 再定義一層函數 _username = 'dandy' # 僞裝是DB抓取的用戶信息 _password = 'password.1' global user_status if user_status == False: username = input("user:") password = input("password:") if username == _username and password == _password: print("Welcome login...") user_status = True else: print("Wrong username or password !") if user_status == True: func(arg1) # 只要驗證經過就會調用相應的功能模塊 return inner # 用戶調用login的時候就會返回inner的內存地址,下次調用加上()纔會執行inner函數
就這樣咱們完成了裝飾器與參數的調用。。。神奇吧。
下面貼上全部的代碼:
1 #!/user/bin/env python 2 # -*- coding: utf-8 -*- 3 4 user_status = False 5 6 7 def login(func): # 把要執行的模塊從這裏傳進來 8 9 def inner(*args, **kwargs): # 再定義一層函數 10 _username = 'dandy' # 僞裝是DB抓取的用戶信息 11 _password = 'password.1' 12 global user_status 13 14 if user_status == False: 15 username = input("user:") 16 password = input("password:") 17 18 if username == _username and password == _password: 19 print("Welcome login...") 20 user_status = True 21 else: 22 print("Wrong username or password !") 23 24 if user_status == True: 25 func(*args, **kwargs) # 只要驗證經過就會調用相應的功能模塊 26 27 return inner # 用戶調用login的時候就會返回inner的內存地址,下次調用加上()纔會執行inner函數 28 29 30 def home(): 31 print("---首頁----") 32 33 34 def america(): 35 print("----歐美專區----") 36 37 38 @login 39 def japan(style): 40 # login()#驗證 41 print("----日韓專區----") 42 43 44 @login 45 def dalu(): 46 # login()#驗證 47 print("----大陸專區----") 48 49 50 japan('3p')
你很開心的帶着代碼去提交給經理。經理侃了也很滿意。
次日,經理又提出了新的需求,須要容許用戶選擇用qq\weixin\weibo 認證。這時候對於你來講一切就沒那麼難了。
#!/user/bin/env python # -*- coding: utf-8 -*- user_status = False def login(auth_type): # 把要執行的模塊從這裏傳進來 def auth(func): def inner(*args, **kwargs): # 再定義一層函數 if auth_type == 'qq': _username = 'dandy' # 僞裝是DB抓取的用戶信息 _password = 'password.1' global user_status if user_status == False: username = input("user:") password = input("password:") if username == _username and password == _password: print("Welcome login...") user_status = True else: print("Wrong username or password !") if user_status == True: func(*args, **kwargs) # 只要驗證經過就會調用相應的功能模塊 else: print('wrong qq auth.') return inner # 用戶調用login的時候就會返回inner的內存地址,下次調用加上()纔會執行inner函數 return auth def home(): print("---首頁----") def america(): print("----歐美專區----") @login('qq') def japan(style): # login()#驗證 print("----日韓專區----") @login('weixin') def dalu(): # login()#驗證 print("----大陸專區----") japan('3p') dalu()
3、Json & Pickle 數據序列化
用於序列化的兩個模塊
· Json,用於字符串 和python數據類型間的轉換
· Pickle,用於python特有類型和python的數據類型間的轉換
Json模塊提供了四個功能:dumps、dump、loads、load
Pickle模塊提供了四個功能:dumps、dump、loads、load
其實Python對於Json所寫的封裝功能已經很完美了,基本沒什麼好講的了上代碼吧:
#!/user/bin/env python # -*- coding: utf-8 -*- import json dict_new = {'name': 'dandy', 'age': 22, 'salary': 30000 } with open("view2", 'w', encoding='utf-8') as fs: json.dump(dict_new, fs)#寫入文件
咱們看下文件
而後
with open('view2', 'r', encoding='utf-8') as fs: dict_new = json.load(fs) print(dict_new) 結果爲: {'name': 'dandy', 'age': 22, 'salary': 30000}
Pickle會加字符串轉換成二進制:
import pickle dict_new = {'name': 'dandy', 'age': 22, 'salary': 30000 } p_str = pickle.dumps(dict_new,) print(p_str) 結果爲一串二進制數: b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x05\x00\x00\x00dandyq\x02X\x03\x00\x00\x00ageq\x03K\x16X\x06\x00\x00\x00salaryq\x04M0uu.' #寫入文件二進制 with open('view3','bw')as fp: pickle.dump(dict_new, fp) #讀取文件 with open('view3','br')as fp: dict_new = pickle.load(fp) print(dict_new) 結果: {'name': 'dandy', 'age': 22, 'salary': 30000}
4、軟件目錄結構規範
爲何要設計好結構目錄?
"設計項目目錄結構",就和"代碼編碼風格"同樣,屬於我的風格問題。對於這種風格上的規範,一直都存在兩種態度:
我是比較偏向於後者的,由於我是前一類同窗思想行爲下的直接受害者。我曾經維護過一個很是很差讀的項目,其實現的邏輯並不複雜,可是卻耗費了我很是長的時間去理解它想表達的意思。今後我我的對於提升項目可讀性、可維護性的要求就很高了。"項目目錄結構"其實也是屬於"可讀性和可維護性"的範疇,咱們設計一個層次清晰的目錄結構,就是爲了達到如下兩點:
因此,我認爲,保持一個層次清晰的目錄結構是有必要的。更況且組織一個良好的工程目錄,實際上是一件很簡單的事兒。
關於如何組織一個較好的Python工程目錄結構,已經有一些獲得了共識的目錄結構。在Stackoverflow的這個問題上,能看到你們對Python目錄結構的討論。
這裏面說的已經很好了,我也不打算從新造輪子列舉各類不一樣的方式,這裏面我說一下個人理解和體會。
假設你的項目名爲foo, 我比較建議的最方便快捷目錄結構這樣就足夠了:
Foo/ |-- bin/ | |-- foo | |-- foo/ | |-- tests/ | | |-- __init__.py | | |-- test_main.py | | | |-- __init__.py | |-- main.py | |-- docs/ | |-- conf.py | |-- abc.rst | |-- setup.py |-- requirements.txt |-- README
簡要解釋一下:
bin/
: 存放項目的一些可執行文件,固然你能夠起名script/
之類的也行。foo/
: 存放項目的全部源代碼。(1) 源代碼中的全部模塊、包都應該放在此目錄。不要置於頂層目錄。(2) 其子目錄tests/
存放單元測試代碼; (3) 程序的入口最好命名爲main.py
。docs/
: 存放一些文檔。setup.py
: 安裝、部署、打包的腳本。requirements.txt
: 存放軟件依賴的外部Python包列表。README
: 項目說明文件。除此以外,有一些方案給出了更加多的內容。好比LICENSE.txt
,ChangeLog.txt
文件等,我沒有列在這裏,由於這些東西主要是項目開源的時候須要用到。若是你想寫一個開源軟件,目錄該如何組織,能夠參考這篇文章。
下面,再簡單講一下我對這些目錄的理解和我的要求吧。
這個我以爲是每一個項目都應該有的一個文件,目的是能簡要描述該項目的信息,讓讀者快速瞭解這個項目。
它須要說明如下幾個事項:
我以爲有以上幾點是比較好的一個README
。在軟件開發初期,因爲開發過程當中以上內容可能不明確或者發生變化,並非必定要在一開始就將全部信息都補全。可是在項目完結的時候,是須要撰寫這樣的一個文檔的。
能夠參考Redis源碼中Readme的寫法,這裏面簡潔可是清晰的描述了Redis功能和源碼結構。
通常來講,用setup.py
來管理代碼的打包、安裝、部署問題。業界標準的寫法是用Python流行的打包工具setuptools來管理這些事情。這種方式廣泛應用於開源項目中。不過這裏的核心思想不是用標準化的工具來解決這些問題,而是說,一個項目必定要有一個安裝部署工具,能快速便捷的在一臺新機器上將環境裝好、代碼部署好和將程序運行起來。
這個我是踩過坑的。
我剛開始接觸Python寫項目的時候,安裝環境、部署代碼、運行程序這個過程全是手動完成,遇到過如下問題:
setup.py
能夠將這些事情自動化起來,提升效率、減小出錯的機率。"複雜的東西自動化,能自動化的東西必定要自動化。"是一個很是好的習慣。
setuptools的文檔比較龐大,剛接觸的話,可能不太好找到切入點。學習技術的方式就是看他人是怎麼用的,能夠參考一下Python的一個Web框架,flask是如何寫的: setup.py
固然,簡單點本身寫個安裝腳本(deploy.sh
)替代setup.py
也何嘗不可。
這個文件存在的目的是:
setup.py
安裝依賴時漏掉軟件包。這個文件的格式是每一行包含一個包依賴的說明,一般是flask>=0.10
這種格式,要求是這個格式能被pip
識別,這樣就能夠簡單的經過 pip install -r requirements.txt
來把全部Python包依賴都裝好了。具體格式說明: 點這裏。
conf.py
放在源碼目錄下,而是放在docs/
目錄下。不少項目對配置文件的使用作法是:
import conf
這種形式來在代碼中使用配置。這種作法我不太贊同:
conf.py
這個文件。因此,我認爲配置的使用,更好的方式是,
可以佐證這個思想的是,用過nginx和mysql的同窗都知道,nginx、mysql這些程序均可以自由的指定用戶配置。
因此,不該當在代碼中直接import conf
來使用配置文件。上面目錄結構中的conf.py
,是給出的一個配置樣例,不是在寫死在程序中直接引用的配置文件。能夠經過給main.py
啓動參數指定配置路徑的方式來讓程序讀取配置內容。固然,這裏的conf.py
你能夠換個相似的名字,好比settings.py
。或者你也可使用其餘格式的內容來編寫配置文件,好比settings.yaml
之類的。
示例代碼 https://github.com/triaquae/py3_training/tree/master/atm
簡易流程圖:https://www.processon.com/view/link/589eb841e4b0999184934329