天天看點

第八章 函數一. 内置函數二、自定義函數

       - 具有特定功能的代碼塊

       - 意義:①簡化代碼重複率;

                     ②功能子產品化

一. 内置函數

       用法: 函數名[參數]

       傳回: 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__)