- 具有特定功能的代碼塊
- 意義:①簡化代碼重複率;
②功能子產品化
一. 内置函數
用法: 函數名[參數]
傳回: seq / None
print, abs,
二、自定義函數
1. 文法格式
def 函數名([參數]):
函數體
[pass 為占位符]
[return 傳回值]
2. 參數使用
--- 函數的參數隻在定義時建立一次,之後再次調用函數,不會給變量新建立記憶體
(1) 位置參數(必須參數)
--- 一旦定義,除預設參數必須按照順序傳入,位置固定
> 位置參數必須放在最前面
(2) 預設參數
--- 給參數賦予預設值,如果不傳入,使用預設值
> 預設形式參數不要使用可變類型,否則重複調時,預設值會被修改
(3) 命名關鍵字參數 - *,
def 函數名(*, 參數名, 參數名...):
#'*,',關鍵字參數和命名關鍵字參數的傳參,必須通過【參數名= 參數值】形式傳入
> 調用
①隻能【參數名= 參數值】形式傳入
②順序不需要固定
> 優點
① 增加程式可讀性
② 忽略參數的作用
③ 當參數有預設值時,等同于預設參數
④ 除了指定預設值,必須傳入參數
(4) 可變參數 - * args
--- 用來收集所用的位置參數,打包成一個元組
def 函數名(* args):
> args 為元組,因為可變參數函數定義時,可以把零散位置參數打包成元組
> 對于元組或者清單(args或者自定義傳入值),應該使用“*”解包
(5) 關鍵字參數 - ** kwargs
--- 把命名關鍵字打包成字典
def 函數名(** kwargs):
(6) 萬能參數
* arg, ** kwargs
注意:
(1) 位置參數必須在最前面
(2) 命名關鍵字參數不能和可變參數放在一起
(3) 優先順序:
位置參數 > 預設參數 > 命名關鍵字參數 / 可變參數 > 關鍵字參數
def fu1(a,b,c=0,*args, **kwargs):
>>> 前三個參數被指派給abc,多餘葡萄普通參數傳入args,輸入關鍵字參數,傳入kwargs
def fu2(a,b,c=0,*,d, **kwargs):
如果有d,關鍵字參數優先傳入d,其他關鍵字優先傳入kwargs
3. 傳回值
> return語句的執行,代表函數的結束
> 傳回值隻能有一個,如果需要多個值,可以以元組傳回;
> 以下傳回值為None
(1) return
(2) reutrn None
(3) 不寫
> 函數最好傳入和傳回值都使用元組等不可變類型
4. 函數中的值傳遞
> 不可變類型的值傳遞
--- 形參指向傳入的實參對象,修改建立新對象,兩者互不影響
> 可變類型的值傳遞
--- 形參指向傳入的實參對象,直接修改對象,函數對實參發生影響
5. 命名空間和作用域
<1> 命名空間
(1) 概念
命名空間 : 可以儲存名字的容器
> 包括:變量名、函數名、類名
> 命名空間中,名字以key-value字典結構存儲,其中key為變量名,value為記憶體位址
> 每一種命名空間都有固定區域
對于函數:
第一次def時,建構命名空間
對于變量:
第一次指派時,建構命名空間
(2) 分類
① 内建命名空間
--- python解釋器啟動的時候建立,解釋器關閉時銷毀
如: sum, print
② 全局命名空間
--- 讀取子產品定義的時候建立,程式運作結束,空間銷毀
如: 全局變量,頂層函數
③ 局部命名空間
--- 在函數建立時建立,函數執行結束時銷毀
如: 局部變量,形式參數, 嵌套函數
注意: 命名空間不存在包含關系,隻存在生命周期,或者說作用域不同。
> 各命名空間建立順序:
python解釋器啟動 ->建立内建命名空間 -> 加載子產品 -> 建立全局命名空間 ->函數被調用 ->建立局部命名空間
> 各命名空間銷毀順序:
函數調用結束 -> 銷毀函數對應的局部命名空間 -> python虛拟機(解釋器)退出 ->銷毀全局命名空間 ->銷毀内建命名空間
<2> 作用域
--- 命名空間中的名字起作用的範圍
① 内建命名空間 --- 整個運作環境所有子產品
② 全局命名空間 --- 僅限目前py檔案,使用其他py檔案需導入
③ 局部命名空間 --- 僅限函數内部有效
注意: 作用域不存在包含關系,隻是大小不同;
檔案名,變量名,函數名...不要用内建命名空間變量名
<3> 通路原則
(1) LEGB原則
> 作用域按照變量的定義位置可以劃分為4類:.
Local (函數内部) 局部作用域
Enclosing(嵌套函數的外層函數内部)嵌套作用域(閉包)
Global (子產品全局) 全局作用域
Built-in (内建) 内建作用域
(2) 名稱的通路
> 讀取 --- LEGB
> 修改 --- 隻從目前最小作用域查找,如果找到修改,找不到建立
globla, nonlocal方法可以修改
> 删除 --- 隻能删除目前命名空間名字
(3) global nonlocal
global --- 局部命名空間修改全局命名空間内容
nonlocal --- 局部命名空間修改外圍命名空間内容
(4) 顯示命名空間
local() --- 可以顯示該語句所在位置的命名空間
global() --- 顯示全局命名空間
eg.
def f():
k = 'asdf'
def inner():
nonlocal k
k = 'qewr'
# del k 報錯,無法删除上一級命名空間
inner()
print(k)
6. lambda表達式(匿名函數)
> 頭等函數: 變量和函數類型、函數名可以被指派、傳遞、和作為傳回值
#函數名指派
def hello():
print('hello')
hello_new = hello
hello_new()
# 函數名當成傳回值
def outer():
def inner():
print('dsaf')
return inner
a = outer()
a()
# 函數名當成值被傳遞
def hello():
print('hello')
def k(m):
pass
k(hello)
(1) 定義
lambda參數: 傳回值表達式
(2) 使用場景
函數體比較簡單
from numpy import square
li = [1, 2, 4]
li.sort(key = lambda x: x**2)
li.sort(key = square)
7. 遞歸
--- 函數調用自身
(1) 直接遞歸
(2) 間接遞歸
遞歸一定要通過條件終止,分為遞推和回歸兩個步驟
> 遞歸和循環
1. 遞歸思路簡單,但是效率比循環低
2. 遞歸有最大深度(所有函數調用次數),default = 1000
最大遞歸次數通過sys.getrecursionlinit()擷取
# 斐波那契數列
def fb(n):
if n ==1 or n ==2:
return 1
else:
return fb(n-1)+fb(n-2)
# for斐波那契數列
# 多元清單解包
# 漢諾塔 - 清單
8. 函數注釋(文檔)
--- 在函數下用三引号
顯示:
> print(函數名.__doc)
> help(函數名)
--- 參數形式的标注
def add(a: int, b:float)->int:
print(函數名.__annotation__)