目錄html
1、基礎概念python
一、裝飾器mysql
一、裝飾器本質就是函數nginx
二、實現裝飾器知識儲備git
一、函數即變量github
二、高階函數sql
三、嵌套函數json
例子flask
一、將一個函數名做爲實參傳遞給另一個函數網絡
二、返回值爲函數名
三、函數嵌套函數
四、完整裝飾器例子
五、裝飾器高級版本
二、列表生成器
三、生成器
四、斐波那契數列
五、迭代器
六、內置函數
七、json、pickle序列化
八、軟件目錄結構規範
1、基礎概念
一、裝飾器:
一、裝飾器本質上就是函數,用來裝飾其餘函數
原則:裝飾器寫好後,原則上不能修改其餘函數源代碼
一、不能修改被裝飾函數源代碼
二、不能修改被裝飾函數調用方式
總結成一點就是裝飾器對被裝飾函數徹底透明,用這個函數的人徹底不知道裝飾器的存在
二、實現裝飾器的知識儲備
一、函數即變量
在python中,變量定義值,在內存中開闢一塊空間存放該變量值,當變量名再也不引用該變量值後,python解釋器會自動回收該值所在內存,函數也是如此,經過函數名調用函數體,當函數名再也不引用該函數體,函數體從內存中被解釋器回收。
二、高階函數
a)把一個函數名做爲實參傳遞給另一個函數,在不修改被裝飾函數源代碼狀況下爲其添加功能
b)返回值爲該函數名,不修改函數的調用方式
三、嵌套函數
在一個函數內經過def聲明一個函數
裝飾器=高階函數+嵌套函數
例子
一、將一個函數名做爲實參傳遞給另一個函數
def test1(func): #傳入函數名做爲實參 func() def bar(): print('in the bar!') test1(bar) #輸出: in the bar!
import time def bar(): print('in the bar!') def test1(func): start_time = time.time() func()# 運行bar函數 stop_time = time.time() print('the func running time is %s' %(stop_time-start_time)) test1(bar) #輸出: in the bar! the func running time is 8.58306884765625e-05
二、返回值爲函數名
import time def bar(): print('in the bar!') def test1(func): print(func) return func bar = test1(bar) #將bar函數名做爲參數傳遞給函數test1內,同時返回值爲bar函數名而不是bar函數執行結果,並將其從新賦值給bar bar() #執行bar()會先執行test1,打印bar對應的內存地址,而後執行bar函數對應的函數體內容 #輸出: <function bar at 0x289a464> in the bar!
三、函數嵌套函數
def foo(): print('in the foo') def bar(): print('in the bar') return bar() #執行foo時會返回bar函數執行結果 foo() #輸出: in the foo in the bar
四、完整裝飾器例子
import time def deco(func): def wrapper(*args,**kwargs): #不管原始函數自身帶任何參數都可以在這包含 start_time = time.time() func(*args,**kwargs) #當test1傳入時,執行test1的返回結果,若是源函數攜帶參數,這裏能夠在執行原函數時帶源函數所帶參數 stop_time = time.time() print('the func time is %s' %(stop_time-start_time)) return wrapper #直接返回函數名 @deco #@deco 等價於 test1 = deco(test1) def test1(name): time.sleep(3) print('in the test1') print('the name is %s' %name) test1('gavin') #輸出: in the test1 the name is gavin the func time is 3.0022261142730713
import time def deco(func): def wrapper(*args,**kwargs): #不管原始函數自身帶任何參數都可以在這包含 start_time = time.time() func(*args,**kwargs) #當test1傳入時,執行test1的返回結果,若是源函數攜帶參數,這裏能夠在執行原函數時帶源函數所帶參數 stop_time = time.time() print('the func time is %s' %(stop_time-start_time)) return wrapper #直接返回函數名 @deco #@deco 等價於 test1 = deco(test1) def test1(name): time.sleep(3) #print('in the test1') #print('the name is %s' %name) return name #返回name值 print(test1('gavin')) #輸出: the func time is 3.0015320777893066 None #用該方法無法返回源函數須要返回的參數
import time def deco(func): def wrapper(*args,**kwargs): #不管原始函數自身帶任何參數都可以在這包含 start_time = time.time() res = func(*args,**kwargs) #當test1傳入時,執行test1的返回結果,若是源函數攜帶參數,這裏能夠在執行原函數時帶源函數所帶參數 stop_time = time.time() print('the func time is %s' %(stop_time-start_time)) return res #當須要被修飾函數有返回值時,能夠在裝飾器中將其返回 return wrapper #直接返回函數名 @deco #@deco 等價於 test1 = deco(test1) def test1(name): time.sleep(3) #print('in the test1') #print('the name is %s' %name) return name print(test1('gavin')) #輸出 the func time is 3.00175404548645 gavin
五、裝飾器高級版本:經過裝飾器來劃分不一樣的登陸認證界面
#版本一,經過不帶參數的auth裝飾器來完成home與bbs認證 user,passwd = 'gavin','123' def auth(func): def wrapper(*args,**kwargs): username = input('usernmae: ').strip() password = input('password: ').strip() if user == username and passwd == password: print('\033[32;1mauthticatin passed\033[32;0m'.center(50,'@')) func(*args,**kwargs) else: exit('wrong input!') return wrapper @auth def home(): print('in the home page!') @auth def bbs(): print('in the bbs page!') home() bbs() #輸出: usernmae: gavin password: 123 @@@@@@@@@authticatin passed@@@@@@@@@ in the home page! usernmae: gavin password: a wrong input!
user,passwd = 'gavin','123' def auth(func): def wrapper(*args,**kwargs): username = input('usernmae: ').strip() password = input('password: ').strip() if user == username and passwd == password: print('\033[32;1mauthticatin passed\033[32;0m'.center(50,'@')) res = func(*args,**kwargs) #將home函數對應的運行結果返回 return res else: exit('\033[31;1mwrong input!\033[32;0m') return wrapper @auth def home(): return 'home page' #須要裝飾器能夠返回該返回值 @auth def bbs(): print('in the bbs page!') print(home()) bbs() #輸出: usernmae: gavin password: 123 @@@@@@@@@authticatin passed@@@@@@@@@ home page usernmae: gavin password: 123 @@@@@@@@@authticatin passed@@@@@@@@@ in the bbs page!
user,passwd = 'gavin','123' def auth(auth_type): #裝飾器攜帶的參數會在第一層傳入裝飾器 def outer(func): #裝飾器要裝飾的源函數會在第二層傳入到裝飾器 def wrapper(*args,**kwargs): if auth_type == 'local': username = input('usernmae: ').strip() password = input('password: ').strip() if user == username and passwd == password: print('\033[32;1mauthticatin passed\033[32;0m'.center(50,'@')) res = func(*args,**kwargs) #將home函數對應的運行結果返回 return res else: exit('\033[31;1mwrong input!\033[32;0m') elif auth_type == 'ldap': print('暫時不支持') func(*args,**kwargs) return wrapper return outer @auth(auth_type = 'local') def home(): return 'home page' #須要裝飾器能夠返回該返回值 @auth(auth_type = 'ldap') def bbs(): print('in the bbs page!') print(home()) bbs() #輸出 usernmae: gavin password: 123 @@@@@@@@@authticatin passed@@@@@@@@@ home page 暫時不支持 in the bbs page!
二、列表生成器
>>> a = [ i * 2 for i in range(10)] >>> a [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
三、生成器:generator
爲了不列表中數據過多佔用太多內存空間,致使系統不可用,使用生成器來替代列表產生數據序列
>>> b = (i * 2 for i in range(10)) >>> b <generator object <genexpr> at 0x10223d7d8>
此時b爲生成器,只有在調用的時候纔會產生數據,因此使用一般的b[5]調用列表的方法是無法獲得數據的
>>> b[2] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'generator' object is not subscriptable
生成器只有在調用時纔會產生相應的數據,同時只記錄當前的位置,只有經過__next__()方式或者next()內置函數才能調用
>>> b.__next__() 0 >>> b.__next__() 2 >>> b.__next__() 4 >>> c = next(b) >>> print(c) 6
>>> b = (i * 2 for i in range(10))
>>> for n in b:print(n) #也可使用for循環一次性所有取出,這樣能夠不用使用next方法同時避免最後遇到StopIteration錯誤
...
0
2
4
6
8
10
12
14
16
18
四、斐波那契數列
fibonacci除了第一個和第二個數外,其餘任意數都是前面兩個數相加獲得的
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b #yield相似斷點,執行到這裏會跳出生成器,而後下一次進入生成器會從這個位置進入繼續執行 a, b = b, a + b #yield會保存函數的中斷狀態 n = n + 1 return 'Done' res = fib(6) for n in res: #一樣斐波那契函數也可使用for循環方式取到全部想要的數值,同時也避免使用next方法,可是有一點for循環無法作到,就是返回return的值 print(n) #輸出 1 1 2 3 5 8
若是想要取到return返回的值,須要使用下面的方法
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b #yield相似斷點,執行到這裏會跳出生成器,而後下一次進入生成器會從這個位置進入繼續執行 a, b = b, a + b #yield會保存函數的中斷狀態 n = n + 1 return 'Done' res = fib(6) while True: try: x = next(res) #next()爲內置函數,相似於__next__() print('res:', x) except StopIteration as e: #若是想要得到return返回的值,必須抓到StopIteration錯誤 print('Generator return valuel:', e.value) break #當結束後會進入exception,同時須要跳出該循環 #輸出 res: 1 res: 1 res: 2 res: 3 res: 5 res: 8
Generator return valuel: Done
經過協程方法達到多線程效果:
#版本一:單獨傳入next與send,查看yield與send方法使用 import time def consumer(name): print('%s準備吃包子啦' %name) while True: baozi = yield #yield保存當前狀態,返回時直接返回到這個狀態,可是單純調用next不會給yield傳值 print('%s包子來啦,被%s吃了!' %(baozi,name)) eat = consumer('gavin') eater = next(eat) #只喚醒yield,不會給它傳值 baozi1 = '韭菜餡' eat.send(baozi1) #send能夠調用yield,同時給yield傳值,也就是喚醒yield同時給它傳值 #輸出 gavin準備吃包子啦 韭菜餡包子來啦,被gavin吃了!
#版本二:經過協程方式達到並行效果 import time def consumer(name): print('%s準備吃包子啦' %name) while True: baozi = yield #yield保存當前狀態,返回時直接返回到這個狀態,可是單純調用next不會給yield傳值 print('%s包子來啦,被%s吃了!' %(baozi,name)) def producter(): c1 = consumer('gavin')#這個動做只是把它變成生成器 c2 = consumer('alex') c1.__next__()#須要執行next纔會執行生成器 c2.__next__() print('老子開始作包子啦!') for i in range(1,5): time.sleep(1) print('作了一個包子,分兩半,一個白菜餡,一個韭菜餡') c1.send(i) c2.send(i) producter() #輸出 gavin準備吃包子啦 alex準備吃包子啦 老子開始作包子啦! 作了一個包子,分兩半,一個白菜餡,一個韭菜餡 1包子來啦,被gavin吃了! 1包子來啦,被alex吃了! 作了一個包子,分兩半,一個白菜餡,一個韭菜餡 2包子來啦,被gavin吃了! 2包子來啦,被alex吃了! 作了一個包子,分兩半,一個白菜餡,一個韭菜餡 3包子來啦,被gavin吃了! 3包子來啦,被alex吃了! 作了一個包子,分兩半,一個白菜餡,一個韭菜餡 4包子來啦,被gavin吃了! 4包子來啦,被alex吃了!
五、迭代器
可直接做用於for循環的數據結構包括:
1:集合類型數據:list、tuple、dict、set、str
二、generator,包括生成器和帶yield的generator function函數
這些能夠直接做用於for循環對象統稱爲可迭代對象Iterable
可使用isinstance()判斷一個對象是不是Iterable
>>> from collections import Iterable >>> isinstance([], Iterable) True >>> isinstance({}, Iterable) True >>> isinstance((), Iterable) True >>> isinstance((x for x in range(20)), Iterable) True
生成器不但能夠做用於for循環,還能夠被next()函數不斷調用並返回下一個值,直到最後拋出StopItrable錯誤表示無法繼續返回下一個值
能夠被next()函數調用並不斷返回下一個值的對象稱爲迭代器Iterator
>>> isinstance((x for x in range(20)), Iterator) True >>> isinstance({}, Iterator) False >>> isinstance([], Iterator) False >>> isinstance((), Iterator) False
生成器都是Iterator對象,可是list dict set雖然是Iterable可是不是Iterator,若是想把它們變爲Iterator,可使用iter()函數
>>> isinstance(iter(()), Iterator) True >>> isinstance(iter([]), Iterator) True >>> isinstance(iter({}), Iterator) True
Python的Iterator
對象表示的是一個數據流,Iterator對象能夠被next()
函數調用並不斷返回下一個數據,直到沒有數據時拋出StopIteration
錯誤。能夠把這個數據流看作是一個有序序列,但咱們卻不能提早知道序列的長度,只能不斷經過next()
函數實現按需計算下一個數據,因此Iterator
的計算是惰性的,只有在須要返回下一個數據時它纔會計算。
Iterator
甚至能夠表示一個無限大的數據流,例如全體天然數。而使用list是永遠不可能存儲全體天然數的。
六、內置函數
>>> abs(-1) #取絕對值 1 >>> print(all([-1])) #若是裏面包括0爲false其他都爲true,這個至關於and,只要有false就爲false True >>> print(all([0,1])) False >>> print(any([0,1])) #只要有真就爲true,無論有沒有false True >>> print(any([0,-1])) True >>> print(ascii('ä¸中å午')) #將值轉換爲asii碼 '\xe4\xb8\u4e2d\xe5\u5348' >>> print(bin(1)) #將十進制轉爲二進制 0b1 >>> bool([]) False >>> bool([1]) #布爾函數,判斷真假 True >>> bool([-1]) True >>> a = bytearray('abcde', encoding='utf-8') #能夠經過asii碼的形式修改字符串 >>> print(a[1]) 98 >>> a[1] = 50 #將b替換爲2 >>> print(a) bytearray(b'a2cde') >>> print(callable([])) #是否能夠包含括號,列表不能包含括號 False >>> def func():print('1') ... >>> print(callable(func)) #函數能夠包含括號 True >>> print(chr(98)) #經過數字獲得對應的asii碼 b >>> print(ord('b'))#經過asii碼獲得對應的數字 98 >>> code = "for i in range(5):print(i)" >>> exec(code) #能夠將字符串對應的函數執行 0 1 2 3 4 >>> >>> >>> a = dict() #定義字典 >>> a {} >>> divmod(5,3) #取兩個數字的商和餘數 (1, 2) >>> a = '''{'a':1,'b':'aaaaa'}''' >>> c = eval(a) #取引號 >>> c {'a': 1, 'b': 'aaaaa'} >>> calc = lambda n:print(n) #匿名函數,若是不反覆調用執行一次就結束可使用匿名函數,執行完畢後當即回收內存 >>> >>> calc(5) 5 >>> calc = lambda n:print(n+1) >>> calc(5) 6 >>> res = filter(lambda n:n>5,range(10)) #過濾器:只取大於5的數值 >>> for i in res:print(i) ... 6 7 8 9 >>> res1 = map(lambda n:n*n,range(5)) #和匿名函數配合 >>> for i in res:print(i) >>> for i in res1:print(i) ... 0 1 4 9 16 >>> import functools #reduce函數從內置函數中去除 >>> res2 = functools.reduce(lambda x,y:x+y,range(10)) #操做x+賦值給x >>> print(res2) 45 >>> float(10) #將整數變爲浮點數 10.0 >>> madlib = " I {verb} the {object} off the {place} ".format(verb="took", object="cheese", place="table") #format是準備替換%s的內置函數,匹配更加精確,經過{}與format方法進行引用,此例format經過變量名進行引用 >>> madlib ' I took the cheese off the table ' >>> '{},{}'.format('a','b') #經過順序方式依次引用a b 'a,b' >>> a = set([1,1,1,1,33,4,1,45]) #將列表變爲集合 >>> a {1, 4, 45, 33} >>> b = frozenset([1,1,1,1,33,4,1,45]) #被凍結的集合,無法添加 >>> b frozenset({1, 4, 45, 33}) >>> print(hash('I have a apple')) #作hash操做 7983704463637394503 >>> len('I have a apple') 14 >>> print(hex(255)) #將十進制轉換爲16進制 0xff >>> def test():local_var = 333,print(locals()) ... >>> test() {} >>> print(globals()) {'test': <function test at 0x101a479d8>, 'res': <filter object at 0x101945b38>, 'functools': <module 'functools' from '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/functools.py'>, '__name__': '__main__', 'a': {1, 4, 45, 33}, '__builtins__': <module 'builtins' (built-in)>, 'b': frozenset({1, 4, 45, 33}), 'res1': <map object at 0x101a534e0>, 'res2': 45, 'c': {'a': 1, 'b': 'aaaaa'}, '__doc__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, 'calc': <function <lambda> at 0x101a478c8>, '__spec__': None, 'i': 16, 'Iterable': <class 'collections.abc.Iterable'>, 'Iterator': <class 'collections.abc.Iterator'>, 'func': <function func at 0x101a477b8>, 'madlib': ' I took the cheese off the table ', 'code': 'for i in range(5):print(i)', '__package__': None} >>> print(globals().get('local_var')) None >>> print(max([1,2,3,4])) #打印最大 4 >>> print(min([1,2,3,4])) #打印最小 1 >>> print(oct(255)) #打印8進制 0o377 >>> a = 'Hello world' #str與repr的區別在於str與repr雖然都是顯示字符串、可是str顯示的更人性化、因此通常和print一塊兒調用,而repr通常是給解釋器使用因此和eval()一塊兒使用的多一些 >>> b = str(a) >>> c = repr(a) #對該字符串再增長引號 >>> d = eval(c) #將c增長的引號脫去 >>> print(a==b) True >>> print(a==c) False >>> print(a==d) True >>> print(str(a)) Hello world >>> print(repr(a)) 'Hello world' >>> print(eval(repr(a))) Hello world >>> print(list(reversed([3,4,55,23,45]))) #對列表裏的數據倒序排列 [45, 23, 55, 4, 3] >>> round(1.3345,3)#去小數點3位 1.335 >>> slice(2,6) slice(2, 6, None) >>> d = range(20) >>> d range(0, 20) >>> d[slice(2,5)] #分割 range(2, 5) >>> sum([1,44,32,11,45])#將列表中的數據相加 133 >>> type([1,44,32,11,45]) #打印數據類型 <class 'list'> >>> a = {6: 2,8:0, 1:4,-5:6,99: 11,4:22} >>> print(a) {1: 4, 99: 11, 4: 22, 6: 2, 8: 0, -5: 6} >>> print(sorted(a.items())) #對字典按照key值來排序 [(-5, 6), (1, 4), (4, 22), (6, 2), (8, 0), (99, 11)] >>> print(sorted(a.items(),key=lambda x:x[1])) #對字典按照value值來排序 [(8, 0), (6, 2), (1, 4), (-5, 6), (99, 11), (4, 22)] >>> print(sorted(a.items(),key=lambda x:x[1],reverse = False ))#對字典按照value值來排序,默認reverse = False採用正序排序 [(8, 0), (6, 2), (1, 4), (-5, 6), (99, 11), (4, 22)] >>> print(sorted(a.items(),key=lambda x:x[1],reverse = True ))#對字典按照value值來排序,reverse = True採用反序排序
[(4, 22), (99, 11), (-5, 6), (1, 4), (6, 2), (8, 0)]
>>> print(sorted(a.items(),reverse = True )) #對字典的key值進行反向排序
[(99, 11), (8, 0), (6, 2), (4, 22), (1, 4), (-5, 6)]
>>> 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')
>>> c = ['a','b']
>>> for i in zip(a,c):print(i) #若是一方的值少,會按照少的那方的數據個數來打印
...
(1, 'a') (2, 'b')
>>> __import__('os') #和import同樣,可是是採用字符串方式來進行引用
<module 'os' from '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/os.py'
> >>> __import__('os',globals(),locals(),['path','pip'])
<module 'os' from '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/os.py'>
七、json、pickle與序列化
用於序列化的兩個模塊
Json模塊提供了四個功能:dumps、dump、loads、load
pickle模塊提供了四個功能:dumps、dump、loads、load
json默認狀況下隻字符串、字典、列表進行序列化,由於json是通用的,全部語言都支持json,在不進行特殊自定義狀況下,不能序列化函數
import json info = { 'name': 'alex', 'age': 23, 'job': 'IT' } print(repr(info)) #輸出 {'job': 'IT', 'name': 'alex', 'age': 23} info_json = json.dumps(info,sort_keys=True) #sort_keys用來對序列進行排序 print(info_json) #輸出 {"age": 23, "job": "IT", "name": "alex"} info_json1 = json.dumps(info,sort_keys=True, indent=4) #indent能夠對dumps的序列進行優化,表示數值離括號的距離 print(info_json1) #輸出 { "age": 23, "job": "IT", "name": "alex" } info_json2 = json.dumps(info,sort_keys=True, separators=(',',':')) #在網絡傳輸過程當中爲了節省傳輸帶寬,能夠對無用的字符進行壓縮,這裏是對,和:進行壓縮以節省更多傳輸空間 print(info_json2) #輸出 {"age":23,"job":"IT","name":"alex"}
import json info = { 'name': 'alex', 'age': 23, 'job': 'IT' } with open('seriliaztion.txt','w') as f: f.write(repr(info)) #按照普通方式寫入文件,普通方式寫入要求字符串格式進行寫入 with open('seriliaztion.txt','r') as f: for line in f: print(type(line)) print(line) #對該形式存入的輸出只能按照字符串方式進行打印 #輸出 <class 'str'> {'age': 23, 'name': 'alex', 'job': 'IT'} with open('seriliaztion-json.txt','w') as f: f.write(json.dumps(info,sort_keys=True)) #在寫入時對其進行json編碼 with open('seriliaztion-json.txt','r') as f: for line in f: print(json.loads(line)['name']) #對此進行解碼,在解碼後能夠按照字典方式針對key打印value print(json.loads(line)['age']) print(json.loads(line)['job']) #輸出 alex 23 IT
with open('seriliaztion-json.txt','r') as f: data = json.load(f) #等同於data = json.loads(f.read())
print(data['job'])
#輸出
IT
#pickle與json的區別在於pickle不須要特殊定義就默認支持將函數序列化,同時pickle生產的文件是二進制文件,須要加b import pickle def sayhi(name): print('hi {}'.format(name)) info = { 'name': 'gavin', 'age': 30, 'func': sayhi } with open('seriliaztion-pickle.txt','wb') as f: #須要加wb pickle.dump(info,f) #等同於f.write(pickle.dumps(info))
八、軟件目錄結構規範
(摘抄於http://www.cnblogs.com/alex3714/articles/5765046.html)
"設計項目目錄結構",就和"代碼編碼風格"同樣,屬於我的風格問題。對於這種風格上的規範,一直都存在兩種態度:
"項目目錄結構"其實也是屬於"可讀性和可維護性"的範疇,設計一個層次清晰的目錄結構,就是爲了達到如下兩點:
因此,保持一個層次清晰的目錄結構是有必要的。更況且組織一個良好的工程目錄,實際上是一件很簡單的事兒。
假設你的項目名爲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
。在軟件開發初期,因爲開發過程當中以上內容可能不明確或者發生變化,並非必定要在一開始就將全部信息都補全。可是在項目完結的時候,是須要撰寫這樣的一個文檔的。
通常來講,用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
之類的。