python基礎06
Python基礎學習06
實現裝飾器知識儲備
裝飾器
生成器
叠代器
目錄結構
一、實現裝飾器知識儲備
1、函數即“變量”
1 x = 1 2 y = 2 3 print(x,y) 4 5 y = 2 6 x = 1 7 print(x,y) 8 9 def bar(): 10 print("in the bar") 11 def foo(): 12 print("in the foo") 13 bar() 14 foo() 15 16 def foo(): 17 print("in the foo") 18 bar() 19View Codedef bar(): 20 print("in the bar") 21 foo()
函數調用順序:其他高級語言類似,Python 不允許在函數未聲明之前,對其進行引用或者調用
python為解釋執行,函數foo在調用前已經聲明了bar和foo,所以bar和foo無順序之分(和變量的調用相同)
2、高階函數
滿足下列條件之一就可成函數為高階函數:
a:把一個函數名當做實參傳給另外一個函數(在不修改被裝飾函數源代碼的情況下為其添加功能)
1 #把一個函數名當做實參傳給另外一個函數 2 def bar(): 3 print("in the bar")View Code4 def test_1 (func): 5 print(func) 6 test_1(bar) #輸出:<function bar at 0x00000264BDEED488> 即bar()函數的內存地址 7 8 def bar(): 9 print("in the bar") 10 def test_1 (func): 11 print(func) #<function bar at 0x00000264BDEED488> 12 func() #in the bar (bar()函數的運行結果) 13 test_1(bar)14 15 #應用:統計函數運行時間 16 import time 17 def bar(): 18 print("in the bar") 19 time.sleep(1) 20 def test_1 (func): 21 start_time = time.time() 22 func() #in the bar (bar()函數的運行結果) 23 stop_time = time.time() 24 print("the func run time:%s "%(stop_time - start_time)) 25 test_1(bar)
b:返回值中包含函數名(不修改函數的調用方式)
1 import time 2 def bar(): 3 print("in the bar") 4 time.sleep(1) 5 def test_2(func): 6 print(func) 7 return func 8 t = test_2(bar) #獲取bar()函數的內存地址,把其當做返回值傳給變量t 9 t() #運行函數 10 11 def bar(): 12 print("in the bar") 13 time.sleep(1) 14 def test_2(func): 15 print(func) 16 return func 17 bar = test_2(bar) #獲取bar()函數的內存地址,把其當做返回值傳給變量bar 18 bar() #不修改函數的調用方式View Code
3、嵌套函數
定義:在一個函數體內創建另外一個函數;即在一個函數的函數體內用def去聲明一個新的函數(而不是去調用)
1 #最簡單的嵌套函數 2 def foo(): 3 print("in the foo") 4 def bar(): #相當於局部變量 5 print("in the bar") 6 bar() #調用bar()函數 7 foo() #調用函數View Code
局部作用域和全局作用域的訪問順序:
1 x=0 2 def grandpa(): 3 # x=1 4 def dad(): 5 x=2 6 def son(): 7 x=3 8 print(x) 9 son() 10 dad() 11 grandpa()View Code
二、裝飾器
定義:本質是函數(裝飾其他函數)就是為其他函數添加附加功能
原則:
a、不能修改被裝飾的函數的源代碼
b、不能修改被裝飾的函數的調用方式
即裝飾器對其裝飾的函數是完全透明的
高階函數+嵌套函數=》裝飾器
簡單裝飾器:(不能傳參)
1 #統計運行時間 2 import time 3 def timer(func): 4 def deco (): 5 start_time = time.time() 6 func() 7 stop_time = time.time() 8 print("the func run time:%s "%(stop_time - start_time)) 9 return deco 10 def test_1 (): 11 time.sleep(1) 12 print("in the test_1") 13 def test_2 (): 14 time.sleep(2) 15 print("in the test_2") 16 17 test_1 = timer(test_1) #即:@timer 18 test_2 = timer(test_2) #即:@timer 19 test_1() #沒有修改被裝飾的函數的源代碼,也沒有修改被裝飾的函數的調用方式,並且添加了新功能 20 test_2() #沒有修改被裝飾的函數的源代碼,也沒有修改被裝飾的函數的調用方式,並且添加了新功能 21 22 #正規寫法 23 import time 24 def timer(func): 25 def deco (): 26 start_time = time.time() 27 func() 28 stop_time = time.time() 29 print("the func run time:%s "%(stop_time - start_time)) 30 return deco 31 @timer #即:test_1 = timer(test_1) 32 def test_1 (): 33 time.sleep(1) 34 print("in the test_1") 35 @timer #即:test_2 = timer(test_2) 36 def test_2 (): 37 time.sleep(2) 38 print("in the test_2") 39 40 test_1() #沒有修改被裝飾的函數的源代碼,也沒有修改被裝飾的函數的調用方式,並且添加了新功能 41 test_2() #沒有修改被裝飾的函數的源代碼,也沒有修改被裝飾的函數的調用方式,並且添加了新功能View Code
加入參數:
1 import time 2 def timer(func): 3 def deco (*args,**kwargs): #deco() 即 test_1、test_2 在此傳入參數 4 start_time = time.time() 5 func(*args,**kwargs) 6 stop_time = time.time() 7 print("the func run time:%s "%(stop_time - start_time)) 8 return deco 9 @timer #即:test_1 = timer(test_1) 10 def test_1 (): 11 time.sleep(1) 12 print("in the test_1") 13 @timer #即:test_2 = timer(test_2) 14 def test_2 (name): 15 time.sleep(0.5) 16 print("test_2",name) 17 18 test_1() 19 test_2("zz")View Code
真正的裝飾器:
1 #在原來函數上添加認證登錄功能,並且允許用戶選擇多種方式進行登錄 2 import time 3 user,passwd = ‘zz‘,‘123‘ 4 def auth(auth_type): 5 def out_wrapper(func): 6 def wrapper(*args,**kwargs): 7 if auth_type == "local": 8 username = input("username:").strip() 9 password = input("password:").strip() 10 if username == user and password ==passwd: 11 print("login!!") 12 res = func(*args,**kwargs) 13 return res #之前的裝飾器沒有返回值,如果有返回值則需要定義返回值 14 else: 15 exit("認證失敗") 16 elif auth_type == "ldap": 17 print("還不會ldap!") 18 return wrapper 19 return out_wrapper 20 21 def index(): 22 print("welcome to index page!") 23 @auth(auth_type = "local") #home = auth() 24 def home(): 25 print("welcome to home page!") 26 return "from home" 27 @auth(auth_type = "ldap") 28 def bbs(): 29 print("welcome to bbs page!") 30 31 index() 32 print(home()) #有返回值的調用 33 bbs()View Code
三、生成器
1、列表生成式
1 a = [1,2,3] #正常定義列表(數據是寫死的) 2 b = [i*2 for i in range(5)] #列表生成式 3 print(b) #[0, 2, 4, 6, 8] 4 5 b = [] #與上面效果一樣但是代碼量大 6 for i in range(5): 7 b.append(i*2) 8 print(b)View Code
2、生成器
在Python中一邊循環一邊計算的機制,稱為生成器:generator。
要創建一個generator,有很多種方法。
第一種方法:只要把一個列表生成式的[]改成(),就創建了一個generator:
1 L = [x * x for x in range(10)] 2 g = (x * x for x in range(10)) 3 print(g) #<generator object <genexpr> at 0x0000022A5A330AF0>View Code
創建L和g的區別僅在於最外層的[]和(),L是一個list,而g是一個generator
我們可以直接打印出list的每一個元素,但我們需要通過next()函數獲得generator的下一個返回值:
1 L = [x * x for x in range(10)] 2 g = (x * x for x in range(10)) 3 print(g) #<generator object <genexpr> at 0x0000022A5A330AF0> 4 5 print(g.__next__()) # 0 6 print(g.__next__()) # 1 7 print(g.__next__()) # 4 8 print(g.__next__()) # 9 9 print(g.__next__()) # 16View Code
generator也是可叠代對象,可以用for循環:
1 g = (x * x for x in range(10)) 2 print(g) #<generator object <genexpr> at 0x0000022A5A330AF0> 3 for i in g : 4 print(i) 5 print(g.__next__()) 6 ‘‘‘ 7 Traceback (most recent call last): 8 print(g.__next__()) # 0 9 StopIteration 10 ‘‘‘View Code
generator保存的是算法,每次調用__next__(g),就計算出g的下一個元素的值,直到計算到最後一個元素,沒有更多的元素時,拋出StopIteration的錯誤
另一種方法:如果一個函數定義中包含yield關鍵字,那麽這個函數就不再是一個普通函數,而是一個generator:
1 #用函數生成斐波那契數列 2 def fib(max): 3 n, a, b = 0, 0, 1 4 while n < max: 5 print(b) 6 a, b = b, a + b 7 ‘‘‘a, b = b, a + b相當於: 8 t = (b, a + b) # t是一個tuple 9 a = t[0] 10 b = t[1] 11 ‘‘‘ 12 n = n + 1 13 return ‘done‘ 14 fib(10) 15 16 #print(b)改為yield b 就變成了生成器 17 def fib(max): 18 n, a, b = 0, 0, 1 19 while n < max: 20 yield b 21 a, b = b, a + b 22 n = n + 1 23 return ‘done‘ 24 print(fib(10)) #<generator object fib at 0x000002371FC30AF0> 25 f = fib(10) 26 print(f.__next__()) # 1 27 print(f.__next__()) # 1 28 print(f.__next__()) # 2 29 print("_____") #_____ 30 print(f.__next__()) # 3View Code
同樣的,把函數改成generator後,我們基本上從來不會用next()來獲取下一個返回值,而是直接使用for循環來叠代,但是用for循環調用generator時,發現拿不到generator的return語句的返回值,計算到最後一個元素,沒有更多的元素時,拋出StopIteration的錯誤,如果想要拿到返回值,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中:
1 def fib(max): 2 n, a, b = 0, 0, 1 3 while n < max: 4 yield b 5 a, b = b, a + b 6 n = n + 1 7 return ‘done‘ 8 g = fib(5) 9 while True: 10 try: 11 x = next(g) 12 print(‘g:‘, x) 13 except StopIteration as e: 14 print(‘Generator return value:‘, e.value) 15 break 16 ‘‘‘ 17 g: 1 18 g: 1 19 g: 2 20 g: 3 21 g: 5 22 Generator return value: done 23 ‘‘‘View Code
特性:a、生成器只有在調用時才會生成數據。
b、只記錄當前位置。
c、只有一個__next__()方法。
四、叠代器
可以直接作用於for循環的對象統稱為可叠代對象:Iterable
可以使用isinstance()判斷一個對象是否是Iterable對象:
1 from collections import Iterable 2 print(isinstance([], Iterable)) #True 3 print(isinstance({}, Iterable)) #True 4 print(isinstance(‘abc‘, Iterable)) #True 5 print(isinstance((x for x in range(10)), Iterable)) #True 6 print(isinstance(100, Iterable)) #FalseView Code
可以被next()函數調用並不斷返回下一個值的對象稱為叠代器:Iterator
可以使用isinstance()判斷一個對象是否是Iterator對象:
1 from collections import Iterator 2 print(isinstance((x for x in range(10)), Iterator)) #True 3 print(isinstance([], Iterator)) #False 4 print(isinstance({}, Iterator)) #False 5 print(isinstance(‘abc‘, Iterator)) #FalseView Code
生成器都是Iterator對象,但list、dict、str雖然是Iterable,卻不是Iterator,把list、dict、str等Iterable變成Iterator可以使用iter()函數:
1 isinstance(iter([]), Iterator) #True 2 isinstance(iter(‘abc‘), Iterator) #TrueView Code
Python的for循環本質上就是通過不斷調用next()函數實現的:
1 for x in [1, 2, 3, 4, 5]: 2 pass 3 #等價於: 4 # 首先獲得Iterator對象: 5 it = iter([1, 2, 3, 4, 5]) 6 # 循環: 7 while True: 8 try: 9 # 獲得下一個值: 10 x = next(it) 11 except StopIteration: 12 # 遇到StopIteration就退出循環 13 breakView Code
五、目錄結構
規範的目錄結構能更好的控制程序結構,讓程序具有更高的可讀性。
"項目目錄結構"其實也是屬於"可讀性和可維護性"的範疇,設計一個層次清晰的目錄結構,就是為了達到以下兩點:
1.可讀性高: 不熟悉這個項目的代碼的人,一眼就能看懂目錄結構,知道程序啟動腳本是哪個,測試目錄在哪兒,配置文件在哪兒等等。從而非常快速的了解這個項目。
2.可維護性高: 定義好組織規則後,維護者就能很明確地知道,新增的哪個文件和代碼應該放在什麽目錄之下。這個好處是,隨著時間的推移,代碼/配置的規模增加,項目結構不會混亂,仍然能夠組織良好。
常用目錄樹:
項目名/
|-- bin/
| |-- 可執行文件
|
|-- 項目/
| |-- tests/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- docs/
| |-- conf.py
| |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README
1.bin/: 存放項目的一些可執行文件。
2.項目/: 存放項目的所有源代碼。(1) 源代碼中的所有模塊、包都應該放在此目錄。不要置於頂層目錄。(2) 其子目錄tests/存放單元測試代碼; (3) 程序的入口最好命名為main.py。
3.docs/: 存放一些文檔。
4.setup.py: 安裝、部署、打包的腳本。
5.requirements.txt: 存放軟件依賴的外部Python包列表。
6.README: 項目說明文件。
README需要說明以下幾個事項:
1.軟件定位,軟件的基本功能。
2.運行代碼的方法: 安裝環境、啟動命令等。
3.簡要的使用說明。
4.代碼目錄結構說明,更詳細點可以說明軟件的基本原理。
5.常見問題說明。
python基礎06