我們首先以一個例子來介紹模塊化編程的應用場景,有這樣一個名為requirements.py的python3文件,其中兩個函數的作用是分別以不同的順序來打印一個字符串:
def example1():
a = 'hello world!'
print (a)
print (a[::-1])
def example2():
b = 'hello again!'
print (b)
print (b[::-1])
if __name__ == '__main__':
example1()
example2()
其執行結果如下所示:
[[email protected]-manjaro decorator]$ python3 requirements.py
hello world!
!dlrow olleh
hello again!
!niaga olleh
在兩個函數中都使用到了同樣的打印功能,這時候我們可以考慮,是不是可以將這兩個打印語句封裝為一個函數呢,這樣不就可以重復利用了?這就是模塊化編程思維的雛形,讓我們先對樣例代碼進行模塊化的改造:
def rprint(para):
print (para)
print (para[::-1])
def example1():
a = 'hello world!'
rprint(a)
def example2():
b = 'hello again!'
rprint (b)
if __name__ == '__main__':
example1()
example2()
這裡我們將兩個打印語句的功能實現封裝進了rprint的函數,執行結果如下:
[[email protected]-manjaro decorator]$ python3 requirements.py
hello world!
!dlrow olleh
hello again!
!niaga olleh
結果當然還是與模塊化之前一致的。
在上一章節中,我們討論了python中的模塊化編程。由於在編程過程中有可能有大量的代碼需要復用,這時候就需要用一個函數來進行封裝,來避免大量重復的工作。但是如果細分來看,這種封裝模式只解決了一類的問題:向下封裝。讓我們再看一次上述改進後樣例中的代碼結構:
.
├── example1
│ └── rprint
└── example2
└── rprint
我們可以發現,這裡復用的rprint實際上屬於兩個example函數的下層,我們可以稱之為向下封裝了一個rprint函數。那麼,如果我們轉換一下需要復用的模塊,變成如下的代碼結構,那我們又需要用什麼樣的方式來實現呢?
.
├── example
│ └── rprint1
└── example
└── rprint2
問題解讀:該代碼結構表示的意義為,有一個大的example函數,該函數內部嵌套不同的rprint函數可以實現不同的功能。為了方便理解,讀者可以想象成是有兩個函數example1和example2,這兩個函數中除了rprint1和rprint2這兩個函數模塊不一致以外,其他的部分都是完全一樣的,也就是可共用的。
首先,我們為了復盤上述章節中的問題,來構造這樣的一個python測試代碼:
def example1():
def rprint1(para):
print (para)
a = 'hello world!'
rprint1(a)
def example2():
def rprint2(para):
print (para[::-1])
a = 'hello world!'
rprint2(a)
if __name__ == '__main__':
example1()
example2()
以上代碼的執行結果為:
[[email protected]-manjaro decorator]$ python3 requirements.py
hello world!
!dlrow olleh
這個案例用到了python中嵌套函數的用法,在函數中可以嵌套實現另外的函數。這裡我們注意到,雖然為了在同一個代碼串中嫩夠運行,兩個example函數的名字取的不同,但是實際上內容是完全相同的,符合上一章節中遺留問題的代碼結構。這裡我們需要考慮的問題是,我們能否做到向上封裝,將example的同樣功能的代碼實現進行歸類?那麼我們需要引入裝飾器的用法,這裡我們直接展示如何構造裝飾器,以及裝飾器使用的效果。
''' 學習中遇到問題沒人解答?小編創建了一個Python學習交流QQ群:857662006 尋找有志同道合的小伙伴,互幫互助,群裡還有不錯的視頻學習教程和PDF電子書! '''
def example(func):
def wrapper(*args, **kwargs):
a = 'hello world!'
return func(a)
return wrapper
@example
def rprint1(para):
print (para)
@example
def rprint2(para):
print (para[::-1])
if __name__ == '__main__':
rprint1()
rprint2()
這個代碼的執行結果為:
[[email protected]-manjaro decorator]$ python3 decorator.py
hello world!
!dlrow olleh
從結果上我們就可以看到,這個代碼是實現了一樣的效果。通過example這個裝飾器,不僅封裝了上層函數中所實現的功能,而且還有一個重大意義是,通過裝飾器向下層函數傳遞了參數。這就使得,我們最終調用rprint函數的時候,不需要傳入任何的參數,因為在example內已經定義了可以共享的參數。
Python的裝飾器並不是一個非常難以實現的特性,其關鍵意義在於實現了向上封裝的模塊化編程。在我們過往的編程實現中,更多的是向下封裝常用的、可復用的代碼模塊。這裡通過Python所提供的裝飾器特性,我們就可以將函數外部所共享的代碼模塊也進行封裝。因此,由函數和裝飾器分別實現的向下封裝與向上封裝的特性,共同構成了提高編碼效率和編碼可讀性提升的模塊化編程模式。