python 函式進階
阿新 • • 發佈:2018-11-08
函式進階
目標
- 函式引數和返回值的作用
- 函式的返回值 進階
- 函式的引數 進階
- 遞迴函式
01. 函式引數和返回值的作用
函式根據 有沒有引數 以及 有沒有返回值,可以 相互組合,一共有 4 種 組合形式
- 無引數,無返回值
- 無引數,有返回值
- 有引數,無返回值
- 有引數,有返回值
定義函式時,是否接收引數,或者是否返回結果,是根據 實際的功能需求 來決定的!
- 如果函式 內部處理的資料不確定,就可以將外界的資料以引數傳遞到函式內部
- 如果希望一個函式 執行完成後,向外界彙報執行結果,就可以增加函式的返回值
1.1 無引數,無返回值
此類函式,不接收引數,也沒有返回值,應用場景如下:
- 只是單純地做一件事情,例如 顯示選單
- 在函式內部 針對全域性變數進行操作,例如:新建名片,最終結果 記錄在全域性變數 中
注意:
- 如果全域性變數的資料型別是一個 可變型別,在函式內部可以使用 方法 修改全域性變數的內容 —— 變數的引用不會改變
- 在函式內部,使用賦值語句 才會 修改變數的引用
1.2 無引數,有返回值
此類函式,不接收引數,但是有返回值,應用場景如下:
- 採集資料,例如 溫度計,返回結果就是當前的溫度,而不需要傳遞任何的引數
1.3 有引數,無返回值
此類函式,接收引數,沒有返回值,應用場景如下:
- 函式內部的程式碼保持不變,針對 不同的引數 處理 不同的資料
- 例如 名片管理系統 針對 找到的名片 做 修改、刪除 操作
1.4 有引數,有返回值
此類函式,接收引數,同時有返回值,應用場景如下:
- 函式內部的程式碼保持不變,針對 不同的引數 處理 不同的資料,並且 返回期望的處理結果
- 例如 名片管理系統 使用 字典預設值 和 提示資訊 提示使用者輸入內容
- 如果輸入,返回輸入內容
- 如果沒有輸入,返回字典預設值
02. 函式的返回值 進階
- 在程式開發中,有時候,會希望 一個函式執行結束後,告訴呼叫者一個結果,以便呼叫者針對具體的結果做後續的處理
- 返回值 是函式 完成工作後,最後 給呼叫者的 一個結果
- 在函式中使用
return
關鍵字可以返回結果 - 呼叫函式一方,可以 使用變數 來 接收 函式的返回結果
問題:一個函式執行後能否返回多個結果?
示例 —— 溫度和溼度測量
- 假設要開發一個函式能夠同時返回當前的溫度和溼度
- 先完成返回溫度的功能如下:
def measure():
"""返回當前的溫度"""
print("開始測量...")
temp = 39
print("測量結束...")
return temp
result = measure()
print(result)
- 在利用 元組 在返回溫度的同時,也能夠返回 溼度
- 改造如下:
def measure():
"""返回當前的溫度"""
print("開始測量...")
temp = 39
wetness = 10
print("測量結束...")
return (temp, wetness)
提示:如果一個函式返回的是元組,括號可以省略
技巧
- 在
Python
中,可以 將一個元組 使用 賦值語句 同時賦值給 多個變數 - 注意:變數的數量需要和元組中的元素數量保持一致
result = temp, wetness = measure()
面試題 —— 交換兩個數字
題目要求
- 有兩個整數變數
a = 6
,b = 100
- 不使用其他變數,交換兩個變數的值
解法 1 —— 使用其他變數
# 解法 1 - 使用臨時變數
c = b
b = a
a = c
解法 2 —— 不使用臨時變數
# 解法 2 - 不使用臨時變數
a = a + b
b = a - b
a = a - b
解法 3 —— Python 專有,利用元組
a, b = b, a
03. 函式的引數 進階
3.1. 不可變和可變的引數
問題 1:在函式內部,針對引數使用 賦值語句,會不會影響呼叫函式時傳遞的 實參變數? —— 不會!
- 無論傳遞的引數是 可變 還是 不可變
- 只要 針對引數 使用 賦值語句,會在 函式內部 修改 區域性變數的引用,不會影響到 外部變數的引用
def demo(num, num_list):
print("函式內部")
# 賦值語句
num = 200
num_list = [1, 2, 3]
print(num)
print(num_list)
print("函式程式碼完成")
gl_num = 99
gl_list = [4, 5, 6]
demo(gl_num, gl_list)
print(gl_num)
print(gl_list)
問題 2:如果傳遞的引數是 可變型別,在函式內部,使用 方法 修改了資料的內容,同樣會影響到外部的資料
def mutable(num_list):
# num_list = [1, 2, 3]
num_list.extend([1, 2, 3])
print(num_list)
gl_list = [6, 7, 8]
mutable(gl_list)
print(gl_list)
面試題 —— +=
- 在
python
中,列表變數呼叫+=
本質上是在執行列表變數的extend
方法,不會修改變數的引用
def demo(num, num_list):
print("函式內部程式碼")
# num = num + num
num += num
# num_list.extend(num_list) 由於是呼叫方法,所以不會修改變數的引用
# 函式執行結束後,外部資料同樣會發生變化
num_list += num_list
print(num)
print(num_list)
print("函式程式碼完成")
gl_num = 9
gl_list = [1, 2, 3]
demo(gl_num, gl_list)
print(gl_num)
print(gl_list)
3.2 預設引數
- 定義函式時,可以給 某個引數 指定一個預設值,具有預設值的引數就叫做 預設引數
- 呼叫函式時,如果沒有傳入 預設引數 的值,則在函式內部使用定義函式時指定的 引數預設值
- 函式的預設引數,將常見的值設定為引數的預設值,從而 簡化函式的呼叫
- 例如:對列表排序的方法
gl_num_list = [6, 3, 9]
# 預設就是升序排序,因為這種應用需求更多
gl_num_list.sort()
print(gl_num_list)
# 只有當需要降序排序時,才需要傳遞 `reverse` 引數
gl_num_list.sort(reverse=True)
print(gl_num_list)
指定函式的預設引數
- 在引數後使用賦值語句,可以指定引數的預設值
def print_info(name, gender=True):
gender_text = "男生"
if not gender:
gender_text = "女生"
print("%s 是 %s" % (name, gender_text))
提示
- 預設引數,需要使用 最常見的值 作為預設值!
- 如果一個引數的值 不能確定,則不應該設定預設值,具體的數值在呼叫函式時,由外界傳遞!
預設引數的注意事項
1) 預設引數的定義位置
- 必須保證 帶有預設值的預設引數 在引數列表末尾
- 所以,以下定義是錯誤的!
def print_info(name, gender=True, title):
2) 呼叫帶有多個預設引數的函式
- 在 呼叫函式時,如果有 多個預設引數,需要指定引數名,這樣直譯器才能夠知道引數的對應關係!
def print_info(name, title="", gender=True):
"""
:param title: 職位
:param name: 班上同學的姓名
:param gender: True 男生 False 女生
"""
gender_text = "男生"
if not gender:
gender_text = "女生"
print("%s%s 是 %s" % (title, name, gender_text))
# 提示:在指定預設引數的預設值時,應該使用最常見的值作為預設值!
print_info("小明")
print_info("老王", title="班長")
print_info("小美", gender=False)
3.3 多值引數(知道)
定義支援多值引數的函式
- 有時可能需要 一個函式 能夠處理的引數 個數 是不確定的,這個時候,就可以使用 多值引數
python
中有 兩種 多值引數:- 引數名前增加 一個
*
可以接收 元組 - 引數名前增加 兩個
*
可以接收 字典
- 引數名前增加 一個
- 一般在給多值引數命名時,習慣使用以下兩個名字
*args
—— 存放 元組 引數,前面有一個*
**kwargs
—— 存放 字典 引數,前面有兩個*
args
是arguments
的縮寫,有變數的含義kw
是keyword
的縮寫,kwargs
可以記憶 鍵值對引數
def demo(num, *args, **kwargs):
print(num)
print(args)
print(kwargs)
demo(1, 2, 3, 4, 5, name="小明", age=18, gender=True)
提示:多值引數 的應用會經常出現在網路上一些大牛開發的框架中,知道多值引數,有利於我們能夠讀懂大牛的程式碼
多值引數案例 —— 計算任意多個數字的和
需求
- 定義一個函式
sum_numbers
,可以接收的 任意多個整數 - 功能要求:將傳遞的 所有數字累加 並且返回累加結果
def sum_numbers(*args):
num = 0
# 遍歷 args 元組順序求和
for n in args:
num += n
return num
print(sum_numbers(1, 2, 3))
元組和字典的拆包(知道)
- 在呼叫帶有多值引數的函式時,如果希望:
- 將一個 元組變數,直接傳遞給
args
- 將一個 字典變數,直接傳遞給
kwargs
- 將一個 元組變數,直接傳遞給
- 就可以使用 拆包,簡化引數的傳遞,拆包 的方式是:
- 在 元組變數前,增加 一個
*
- 在 字典變數前,增加 兩個
*
- 在 元組變數前,增加 一個
def demo(*args, **kwargs):
print(args)
print(kwargs)
# 需要將一個元組變數/字典變數傳遞給函式對應的引數
gl_nums = (1, 2, 3)
gl_xiaoming = {"name": "小明", "age": 18}
# 會把 num_tuple 和 xiaoming 作為元組傳遞個 args
# demo(gl_nums, gl_xiaoming)
demo(*gl_nums, **gl_xiaoming)
04. 函式的遞迴
函式呼叫自身的 程式設計技巧 稱為遞迴
4.1 遞迴函式的特點
特點
- 一個函式 內部 呼叫自己
- 函式內部可以呼叫其他函式,當然在函式內部也可以呼叫自己
程式碼特點
- 函式內部的 程式碼 是相同的,只是針對 引數 不同,處理的結果不同
- 當 引數滿足一個條件 時,函式不再執行
- 這個非常重要,通常被稱為遞迴的出口,否則 會出現死迴圈!
示例程式碼
def sum_numbers(num):
print(num)
# 遞迴的出口很重要,否則會出現死迴圈
if num == 1:
return
sum_numbers(num - 1)
sum_numbers(3)
4.2 遞迴案例 —— 計算數字累加
需求
- 定義一個函式
sum_numbers
- 能夠接收一個
num
的整數引數 - 計算 1 + 2 + ... num 的結果
def sum_numbers(num):
if num == 1:
return 1
# 假設 sum_numbers 能夠完成 num - 1 的累加
temp = sum_numbers(num - 1)
# 函式內部的核心演算法就是 兩個數字的相加
return num + temp
print(sum_numbers(2))
提示:遞迴是一個 程式設計技巧,初次接觸遞迴會感覺有些吃力!在處理 不確定的迴圈條件時,格外的有用,例如:遍歷整個檔案目錄的結構