函數
函數定義:
函數是指將一組語句的集合通過一個名字封裝起來,要想執行這個函數只需要調用其函數名即可.
函數特性:
1.減少重復代碼
2.使程序變的可擴展性
3.使程序變的易維護
函數語法定義:
def name(): # 函數名 print('hello, world') name() # 調用
帶參數的函數
# 下面這段代碼 a,b = 5,8 c = a**b print(c) # 改成用函數寫 def calc(x,y): res = x**y return res # 返回函數執行結果 c = calc(a,b) # 結果賦值給c變量 print(c)
函數參數:
形參:只有在被調用的才分配內存單元,在調用結束時,即刻釋放所分配的內存單元.因此,形參只在函數內部有效,函數調用結束后返回主調用函數后不能再使用該形參變量.
實參:可以是常量,變量,表達式,函數等.無論實參是何種類型的量,在進行函數調用時,它都必須有確定的值以便把這些值傳給形參,因此應預先用賦值,輸入等辦法使參數獲得確定值
位置參數:
在調用的時候必須和參數位置順序對應
def stu_register(name, age, country, course): print("----注冊學生信息------") print("姓名:", name) print("age:", age) print("國籍:", country) print("課程:", course) stu_register("王山炮", 22, "CN", "python") stu_register("張叫春", 21, "CN", "linux") stu_register("劉老根", 25, "CN", "linux")
默認參數:
country在參數中定義了值,這個參數在調用時不指定,那默認就是CN,指定了的話,就用你指定的值.
def stu_register(name, age, course, country='CN'): print("----注冊學生信息------") print("姓名:", name) print("age:", age) print("國籍:", country) print("課程:", course) stu_register("王山炮", 22, "python") stu_register("張叫春", 21, "linux") stu_register("劉老根", 25, "linux", 'Korean') # 調用的時候不寫country默認為CN
關鍵參數:
調用的時候不想按順序就可以用關鍵參數,注意的是,關鍵參數必須放在位置參數之后
def stu_register(name, age, course='PY', country='CN'): print("----注冊學生信息------") print("姓名:", name) print("age:", age) print("國籍:", country) print("課程:", course) stu_register("王三炮", course="PY", age=22, country="China") # 調用的時候不想按順序就可以用關鍵參數
非固定參數:
*args
如果參數中出現*args,傳遞的參數就可以不再是固定參數,傳過來的所有參數打包成元祖形式.
def stu_register(name, age, *args): # *args 會把多傳入的參數變成一個元組形式 print(name, age, args) stu_register("Alex", 22) # 輸出:Alex 22 (),后面這個(),就是args,只是因為沒傳值,所以為空 stu_register("Jack", 32, "Linux", "Go") # 輸出:Jack 32 ('Linux', 'Go')
如果 調用方法的時候,*args傳入["Linux", "Go"],打印結果:(["linux"])---->*args傳入*["Linux", "Go"],打印結果("Linux", "Go")
**kwargs
如果參數中出現**kwargs,傳遞的參數就可以不再試固定個數,傳過來的所有參數打包成字典形式
def stu_register(name, age, *args, **kwargs): # *kwargs 會把多傳入的參數變成一個dict形式 print(name, age, args, kwargs) stu_register("Alex", 22) # 輸出:Alex 22 () 后面這個{}就是**kwargs,只是因為沒傳值,所以為空 stu_register("Jack", 32, "CN", "Python", sex="Male", province="ShanDong") # 輸出:Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}
def stu_register(name, age, *args, **kwargs): # *kwargs 會把多傳入的參數變成一個dict形式 print(name, age, args, kwargs) stu_register("Alex", 22) # 輸出:Alex 22 () 后面這個{}就是**kwargs,只是因為沒傳值,所以為空 d = {'degree': 'primary school'} stu_register('王小二', 8, 'python', **d) # 輸出:王小二 8 ('python',) {'degree': 'primary school'}
定義:d = {'degree': 'primary school'},如果調用方法的時候,傳入stu_register('王二小', 8, d),打印:王二小 8 ({'degree': 'primary school'},) {}--->**d,輸出字典王二小 8 () {'degree': 'primary school'}
函數的返回值:
def stu_register(name, age, course): print(name, age, course) if age > 22: return False else: return [name, age] # 默認返回元祖,加上指定類型返回該類型數據 status = stu_register('ike', 20, 'Python') print(status)
# 輸出
ike 22 Python
['ike', 22]
注:函數在執行過程中只要遇到return語句,就會停止執行並返回結果,所以也可以理解為 return 語句代表着函數的結束
如果為在函數中指定return,那這個函數的返回值為None
局部與全局變量:
局部變量就是指定義在函數里的變量,只能在局部生效.
全局變量就是指在函數外部一級代碼的變量,叫做全局變量,全局都能用.
注:在函數內部,可以引用全局變量,如果全局和局部都有一個變量,叫name,函數會查找的順序,由內而外.
name = '函數外邊' # 局部變量-->函數里面定義的變量--函數里print從里到外找name def change_name(): name = '函數里邊' print('在', name, id(name)) change_name() print(name, id(name))
局部golbal可以修改全局變量
name = '函數外邊' # 局部變量-->函數里面定義的變量--函數里print從里到外找name def change_name(): global name name = '函數里邊' print('在', name, id(name)) change_name() print(name, id(name))
# 打印結果
在 函數里邊 10435328
函數里邊 10435328
函數內部有del方法,全局變量相應刪除
name = ['黑姑娘', 'alex', 'pei qi'] # 局部變量-->函數里面定義的變量--函數里print從里到外找name def change_name(): del name[0] # name = ['pei qi', 'alex'] print('在', name, '里邊...', id(name)) change_name() print(name, id(name))
嵌套函數:
1.函數內部可以再次定義函數
2.執行需要被調用(內部也需要調用)
func0 = 'ike' def func1(): print('alex') def func2(): print('jack') func2() func1() print(func0)
函數里邊的age = 73,分別放在調用最里層的函數上下輸出
age = 19 def func1(): global age def func2(): print(age) age = 73 # 放在調用func2()最里層下邊,打印 19 73, 放在調用func2()上邊,打印 73 73 func2() func1() print(age)
作用域:
作用域(scope),程序設計概念,通常來說,一段程序代碼中所用到的名字並不總是有效/可用的,而限定這個名字的可用性的代碼范圍就是這個名字的作用域。
匿名函數:
1.節省代碼量
2.看着高級
data = list(range(10)) print(data) print(list(map(lambda x: x*x, data)))
def calc(x, y): if x > y: return x*y else: return x/y # 聲明一個匿名函數 等同與上邊的函數 func = lambda x, y: x*y if x < y else x/y print(func(3, 8))
print(list(map(lambda x: x*x if x > 5 else x, range(10))))
高階函數:
變量可以指向函數,函數的參數能接收變量,那么一個函數就可以接收另一個函數作為參數,這種函數就稱之為高階函數。
def func(x, y): return x, y def calc(x): return x f = calc(func) print(f(5, 9))
def add(x, y, f): return f(x) + f(y) res = add(3, -6, abs) print(res)
滿足以下任意一個條件,即是高級函數
1.接收一個或多個函數作為輸入
2.return返回另外一個函數
遞歸:
在函數內部,可以調用其他函數。如果一個函數在內部調用自己本身,這個函數就是遞歸函數。
def calc(n): print(n) if int(n/2) ==0: return n return calc(int(n/2)) calc(10) 輸出 10 5 2 1
遞歸的特征:
1.必須有一個明確的結束條件
2.每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
3.遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數
調用是通過棧(stack)這種數據結構實現的,每當進入一個函數
調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。
由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)
# 階乘 def factorial(n): if n == 1: # 有一個明確的結束條件 return 1 return n * factorial(n-1) # 2+6+12 print(factorial(7))
尾遞歸
def cal(n): print(n) return cal(n+1) cal(1)
return的數據和上一層沒有任何的關系.
內置函數: