一、函數
當我們在編寫程序時。可能會遇到某些功能相似的代碼。此時爲了減少代碼冗餘,我們可以使用將功能相似的代碼寫成一個函數,並在適當的位置調用。
二、函數定義
引入一個關鍵字 def
用於定義一個函數
- 它必須後跟函數名稱和帶括號的形式參數列表。
- 構成函數體的語句從下一行開始,並且必須縮進。
- 函數體的第一個語句可以(可選的)是字符串文字; 它是函數文檔字符串, 用於解釋函數的功能, 及參數和返回值的含義
- 函數的 執行 會引入一個用於函數局部變量的新符號表。 更確切地說,函數中所有的變量賦值都將存儲在局部符號表中;
- 變量引用會首先在局部符號表中查找,
- 然後是外層函數的局部符號表,
- 再然後是全局符號表,
- 最後是內置名稱的符號表
語法規則
def function_name(形參列表):
"""函數文檔""" [可選]
函數執行的代碼
return 返回值
- 函數被調用時,實際參數會被引入被調用函數的本地符號表中;實參是通過 按值調用傳遞的
- 其中
值
始終是對象引用
: 即使對象的id
- 而不是對象的值
- 函數調用是通過
函數名(形參列表)
形式調用
- 其中
- 當一個函數調用另外一個函數時,將會爲該調用創建一個新的本地符號表。
- 即使沒有
return
語句的函數也會返回一個值,這個值稱爲None
(它是內置名稱)
示例程序
def fib(n):
a, b = 0, 1
while a < n:
print(a, end=" ")
a, b = b, a+b
print()
fib(10) # 函數調用
def fib2(n):
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
print(fib2(10))
三、函數的參數形式
上面示例程序中的函數參數是必備參數形式
. 即在調用函數時, 必須傳入參數到函數中. 否則會報錯.
3.1 空參數形式
函數不需要參數就能被調用.
def printf():
print("hello world")
3.2 參數默認值
對一個或多個參數指定一個默認值。這樣創建的函數,可以用比定義時允許的更少的參數調用.
def function_name(agr1=value1,arg2=value2):
函數內執行代碼
- 默認值是在函數定義處計算
i = 10 def print_i(arg=i): print(arg) # 輸出的是10 print(i) # 輸出6 i = 6 print_i()
- 默認值只會執行一次
def fun(a, L=[]): L.append(a) return L print(fun(1)) # 輸出[1] print(fun(2)) # 輸出[1, 2] print(fun(3)) # 輸出[1, 2, 3]
- 如果你不想要在後續調用之間 共享默認值, 函數進行如下定義:
def fun(a, L=None): if L is None: L = [] L.append(a) return L print(fun(1)) # 輸出[1] print(fun(2)) # 輸出[2] print(fun(3)) # 輸出[3]
3.3 不定長參數形式
有時候函數需要很多的參數, 如果全部顯示寫出來會顯得函數定義臃腫. 可以使用不定長參數來定義函數
語法如下
def function_name(*args, **kwargs):
函數內執行代碼
*args
當以變量形式直接傳入多個參數時,會被*args
接收並打包成元組的形式存在args中傳入函數內。**kwargs
當以映射(默認參數)的形式傳入參數時,會被**kwargs
接收並打包成字典形式存在kwargs中傳入函數內
- 元組和字典之後講解
3.4 特殊參數/
*
默認情況下,函數的參數傳遞形式可以是位置參數或是顯式的關鍵字參數。 爲了確保可讀性和運行效率,限制允許的參數傳遞形式是有意義的,這樣開發者只需查看函數定義即可確定參數項是僅按位置、按位置也按關鍵字,還是僅按關鍵字傳遞。
函數的定義看起來可以像是這樣:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
- 如果函數定義中未使用
/
和*
,則參數可以按位置或按關鍵字傳遞給函數。 - 如果使用了
/
, 則/
之前的參數只能通過位置傳參; 之後的參數可以通過位置傳參, 也可以同關鍵字傳參 - 如果使用了
*
, 則*
之後的參數必須以關鍵字傳參
3.5 解包參數
- 通過
*
操作符來將列表或元組解包用於位置參數傳遞 - 通過
**
操作符來將字典解包用於關鍵字參數的傳遞
四、函數的標註
針對函數參數和返回值類型的說明
語法格式如下
def function_name(arg1: 類型, arg2: 類型 = "默認值")-> 類型:
函數執行的代碼
五、閉包
閉包是指在函數內部嵌套一個函數,可由外層函數返回內層函數的函數名。
def func():
def text():
print("hello world")
return text
text = func() # 調用外層函數獲取內層函數函數名
text() # 調用內層函數。
閉包是函數裏面嵌套函數,外層函數返回裏層函數,這種情況稱之爲閉包
閉包是概念,不是某種函數類型,和遞歸的概念類似,就是種特殊的函數調用
閉包可以得到外層函數的局部變量,是函數內部和函數外部溝通的橋樑
六、變量的作用域
- 函數內部可以查看函數外部的變量, 但是不能修改函數外部變量.
- 函數內部變量不能在函數外部使用.
全局變量
可以在程序任意位置訪問的的變量稱爲全局變量.
局部變量
只能在特定位置訪問的變量稱爲局部變量. 比如函數內的定義的變量, 控制語句中定義的變量.
6.1 全局變量的使用
python中函數內部是不能修改函數外部的變量的. 要使用關鍵字global
在函數內部聲明全局變量, 才能對全局變量進行修改
global_int = 12
def func():
global global_int
global_int += 1
print('函數內部',global_int)
func()
print('函數外部',global_int)
6.2 局部變量的使用
定義在函數內部的變量. 如果內層函數要修改外層函數的變量使用關鍵字nonlocal
聲明局部變量, 這樣才能在內層函數修改外層函數的變量
def glo():
test_non = 34
print("外部函數", test_non)
def test():
nonlocal test_non
test_non += 1
print('內部測試函數', test_non)
return test
glo()()