Py函数直接传入root是啥意思_Python内部函数——用处何在?
1. 封裝
內部函數可以免受函數之外的情況的影響,也就是說,對于全局命名空間而言,它們是隱藏的。
下面是一個簡單的例子:
def outer(num1):def inner_increment(num1): # 對外部空間隱藏return num1 + 1num2 = inner_increment(num1)print(num1, num2)inner_increment(10) # outer(10)如果我們直接調用 inner_increment() 函數,會有報錯信息:
Traceback (most recent call last):File "inner.py", line 7, in <module>inner_increment() NameError: name 'inner_increment' is not defined注釋掉對 inner_increment() 的直接調用,對外部的函數傳入參數 10,即 outer(10) 是可以運行的:
10 11注意:這只是一個例子,雖然這些代碼可以運作,但就這個函數而言,可能更好的方式是把 inner_increment() 定義為存在于外部空間的“私有”函數,即在函數名前加一個下劃線前綴,即 _inner_increment() 。下面這個嵌套函數可能是一個更好的使用內部函數的例子:
def factorial(number):# 處理錯誤if not isinstance(number, int):raise TypeError("Sorry. 'number' must be an integer.")if not number >= 0:raise ValueError("Sorry. 'number' must be zero or positive.")def inner_factorial(number):if number <= 1:return 1return number*inner_factorial(number-1)return inner_factorial(number) # 調用外部函數 print(factorial(4))在這里,我們把參數驗證放在外部函數,而在內部函數中處理關鍵步驟。
2. 避免自我重復(DRY原則)
有時,我們可能會在一個大型函數中,重復地使用一些代碼。比方說,我們寫一個處理文件的函數,同時支持文件名或文件對象作為參數:
def process(file_name):def do_stuff(file_process):for line in file_process:print(line)if isinstance(file_name, str):with open(file_name, 'r') as f:do_stuff(f)else:do_stuff(file_name)注意:再次提醒,可能更常見的情況是,我們直接把 do_stuff() 放在外部,作為一個私有函數,但顯然,必要時我們也可以把它作為內部函數隱藏起來。我們可以寫一個更具體的例子。
假如說,我們想了解紐約市的 WIFI 熱點數據,可以直接在網上下載對應的 CSV 文件,然后進行統計:
def process(file_name):def do_stuff(file_process):wifi_locations = {}for line in file_process:values = line.split(',') # 創建一個字典,記錄統計數據 wifi_locations[values[1]] = wifi_locations.get(values[1], 0) + 1max_key = 0for name, key in wifi_locations.items():all_locations = sum(wifi_locations.values())if key > max_key:max_key = keybusiness = nameprint(f'紐約市總共有 {all_locations} 個 WIFI 熱點,'f'{business} 提供的熱點最多,有 {max_key} 個。')if isinstance(file_name, str):with open(file_name, 'r') as f:do_stuff(f)else:do_stuff(file_name)運行后得到結果如下:
>>> process('NAME_OF_THE.csv') 紐約市總共有 1251 個 WiFi 熱點,Starbucks 提供的熱點最多,有 212 個。3. 閉包與工廠函數
接下來我們要討論的是使用內部函數最重要的理由。在之前的例子中,內部函數都是一個常規函數,只是恰好被嵌套在另一個函數中而已。也就是說,我們完全用其它方式定義它們(如之前已經提示的),并非一定要使用內部函數。
而在考慮閉包的時候,我們就必須使用嵌套函數了。
什么是閉包
閉包可以使內部函數記住它所在空間的具體狀態。新手們常常以為內部函數就是閉包,準確地說,應該是內部函數制造了閉包。所謂閉包,所“封閉”的是函數幀中的局部變量。
一個例子
以下是一個例子:
def generate_power(number):""" Examples of use:>>> raise_two = generate_power(2)>>> raise_three = generate_power(3)>>> print(raise_two(7))128>>> print(raise_three(5))243"""# 定義內部函數def nth_power(power):return number ** power# 將函數作為外部函數的結果返回return nth_power對例子的解釋
讓我們看看這個例子中具體發生了什么:
- 調用外部函數:generate_power(2);
- 創建函數 nth_power(),它需要一個參數 power;
- 保存 nth_power() 函數幀的狀態,其中包括 number=2;
- 將保存的函數幀狀態傳遞給 generate_power() 函數;
- 返回 nth_power() 函數;
換句話說,閉包為 nth_power() 函數提供了初始化數據并將它返回。因此,我們調用這個被返回的函數時,總是可以在其函數幀中找到 number=2。
一個實際應用
現在,讓我們考慮一個真實世界中的例子:
def has_permission(page):def inner(username):if username == 'Admin':return "'{0}' does have access to {1}.".format(username, page)else:return "'{0}' does NOT have access to {1}.".format(username, page)return innercurrent_user = has_permission('Admin Area') print(current_user('Admin'))random_user = has_permission('Admin Area') print(random_user('Not Admin'))這是一個簡化版的權限判斷函數,我們也可以做簡單修改,從 session 中獲取用戶信息,進而判斷這個用戶是否具有接入某個路由的權限。顯然,我們會從數據庫中查詢用戶權限,而不是檢查用戶名是否等于 'Admin'。
總結
閉包與函數工廠是內部函數最常見、最主要的用處。大多數情況下,如果你看到一個帶裝飾器的函數,這個裝飾器就是一個函數工廠,它以一個函數作為參數,并返回一個新的函數,新的函數使用閉包包括了作為參數的函數。
換句話說,裝飾器就是一個語法糖,它的基本流程其實和上面所舉的 generate_power() 的例子是一致的。
以下是最后一個例子:
def generate_power(exponent):def decorator(f):def inner(*args):result = f(*args)return exponent**resultreturn innerreturn decorator@generate_power(2) def raise_two(n):return n print(raise_two(7))@generate_power(3) def raise_three(n):return n print(raise_two(5))如果你的代碼編輯器允許的話,可以嘗試把 generate_power(exponent) 和 generate_power(number) 并排對比,以理解我們所討論的概念。(比如說,可以用 Sublime Text 中的分欄功能)
如果你還沒寫出這兩個函數的話,建議還是親自在編輯器中敲出來一次,對編程新手來說,寫代碼就行騎自行車:你必須親自上手。
敲出這些代碼后,你就能看出,它們產生了類似的結果,但也有一些不同。對于還沒有用過裝飾器的人來說,注意到這些不同,就是理解它們的開始。
END
公眾號:ReadingPython
總結
以上是生活随笔為你收集整理的Py函数直接传入root是啥意思_Python内部函数——用处何在?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微pe Linux,微PE工具箱:最好用
- 下一篇: vld检测不输出_输出轴热处理形变超差,