1. 程式人生 > >Python學習之路6?函數,遞歸,內置函數

Python學習之路6?函數,遞歸,內置函數

erro memory 子程序 none 種類 lan 萬年 字典 得到

一python中的函數

函數是邏輯結構化和過程化的一種編程方法。

python中函數定義方法:
 
def test(x):
    "The function definitions"
    x+=1
    return x
     
def:定義函數的關鍵字
test:函數名
():內可定義形參
"":文檔描述(非必要,但是強烈建議為你的函數添加描述信息)
x+=1:泛指代碼塊或程序處理邏輯
return:定義返回值


調用運行:可以帶參數也可以不帶
函數名()

二 為何使用函數

背景提要

現在老板讓你寫一個監控程序,監控服務器的系統狀況,當cpu\memory\disk等指標的使用量超過閥值時即發郵件報警,你掏空了所有的知識量,寫出了以下代碼

 1 while True:
 2     if cpu利用率 > 90%:
 3         #發送郵件提醒
 4         連接郵箱服務器
 5         發送郵件
 6         關閉連接
 7      
 8     if 硬盤使用空間 > 90%:
 9         #發送郵件提醒
10         連接郵箱服務器
11         發送郵件
12         關閉連接
13      
14     if 內存占用 > 80%:
15         #發送郵件提醒
16         連接郵箱服務器
17         發送郵件
18 關閉連接

上面的代碼實現了功能,你這個重復代碼太多了,每次報警都要重寫一段發郵件的代碼,太low了,這樣幹存在2個問題:

  1. 代碼重復過多,一個勁的copy and paste不符合高端程序員的氣質
  2. 如果日後需要修改發郵件的這段代碼,比如加入群發功能,那你就需要在所有用到這段代碼的地方都修改一遍

其實很簡單,只需要把重復的代碼提取出來,放在一個公共的地方,起個名字,以後誰想用這段代碼,就通過這個名字調用就行了,如下

 1 def 發送郵件(內容)
 2     #發送郵件提醒
 3     連接郵箱服務器
 4     發送郵件
 5     關閉連接
 6      
 7
while True: 8 9 if cpu利用率 > 90%: 10 發送郵件(CPU報警) 11 12 if 硬盤使用空間 > 90%: 13 發送郵件(硬盤報警) 14 15 if 內存占用 > 80%: 16 發送郵件(內存報警)

總結使用函數的好處:

1.代碼重用

2.保持一致性,易維護

3.可擴展性

三 函數和過程

過程定義:過程就是簡單特殊沒有返回值的函數

這麽看來我們在討論為何使用函數的的時候引入的函數,都沒有返回值,沒有返回值就是過程,沒錯,但是在python中有比較神奇的事情

 1 def test01():
 2     msg=hello The little green frog
 3     print msg
 4  
 5 def test02():
 6     msg=hello WuDaLang
 7     print msg
 8     return msg
 9  
10  
11 t1=test01()
12  
13 t2=test02()
14  
15  
16 print from test01 return is [%s] %t1
17 print from test02 return is [%s] %t2

總結:當一個函數/過程沒有使用return顯示的定義返回值時,python解釋器會隱式的返回None,

所以在python中即便是過程也可以算作函數。

 1 def test01():
 2     pass
 3  
 4 def test02():
 5     return 0
 6  
 7 def test03():
 8     return 0,10,hello,[alex,lb],{WuDaLang:lb}
 9  
10 t1=test01()
11 t2=test02()
12 t3=test03()
13  
14  
15 print from test01 return is [%s]:  %type(t1),t1
16 print from test02 return is [%s]:  %type(t2),t2
17 print from test03 return is [%s]:  %type(t3),t3

總結:

返回值數=0:返回None

返回值數=1:返回object

返回值數>1:返回tuple

四 函數是第一類對象

在python中所有的名字都沒有儲值功能

函數是第

1 def foo():
2     print("yyp")
3 f1=foo
4 f1()
5 # 輸出結果:
6 yyp

可以當做參數

 1 def foo():
 2     print("tom")
 3 
 4 def func(msg):
 5     print(msg)
 6     msg()
 7 
 8 func(foo)
 9 輸出結果:
10 <function foo at 0x00000000020D3E18>
11 tom

可以當做返回值

 1 def foo():
 2     print("tom")
 3 
 4 def func(msg):
 5     return msg
 6 
 7 f=func(foo)
 8 print(f)
 9 f()
10 輸出結果:
11 <function foo at 0x0000000002423E18>
12 tom

可以當做容器類型的一個元素

1 def foo():
2     print("tom")
3 
4 func_dic={
5     foo:foo
6 }
7 輸出結果:
8 tom

一類對象指的是:函數可以被當做數據來處理被引用

五 函數參數

1.形參變量只有在被調用時才分配內存單元,在調用結束時,即刻釋放所分配的內存單元。因此,形參只在函數內部有效。函數調用結束返回主調用函數後則不能再使用該形參變量

2.實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須有確定的值,以便把這些值傳送給形參。因此應預先用賦值,輸入等辦法使參數獲得確定值

技術分享

3.位置參數和關鍵字(標準調用:實參與形參位置一一對應;關鍵字調用:位置無需固定)

4.默認參數

5.參數組

六 局部變量和全局變量

在子程序中定義的變量稱為局部變量,在程序的一開始定義的變量稱為全局變量。

全局變量作用域是整個程序,局部變量作用域是定義該變量的子程序。 當全局變量與局部變量同名時: 在定義局部變量的子程序內,局部變量起作用;在其它地方全局變量起作用。
 1 name=lhf
 2 
 3 def change_name():
 4     print(我的名字,name)
 5 
 6 change_name()
 7 
 8 
 9 def change_name():
10     name=帥了一筆
11     print(我的名字,name)
12 
13 change_name()
14 print(name)
15 
16 
17 
18 def change_name():
19     global name
20     name=帥了一筆
21     print(我的名字,name)
22 
23 change_name()
24 print(name)

七 前向引用之‘函數即變量‘

 1 def action():
 2     print in the action
 3     logger()
 4 action()
 5 報錯NameError: global name logger is not defined
 6 
 7 
 8 def logger():
 9     print in the logger
10 def action():
11     print in the action
12     logger()
13  
14 action()
15  
16 
17 def action():
18     print in the action
19     logger()
20 def logger():
21     print in the logger
22  
23 action()

八 嵌套函數和作用域

看上面的標題的意思是,函數還能套函數?of course

 1 name = "yyp"
 2  
 3 def change_name():
 4     name = "yyp2"
 5  
 6     def change_name2():
 7         name = "yyp3"
 8         print("第3層打印",name)
 9  
10     change_name2() #調用內層函數
11     print("第2層打印",name)
12  
13  
14 change_name()
15 print("最外層打印",name)

此時,在最外層調用change_name2()會出現什麽效果?

沒錯, 出錯了, 為什麽呢?

作用域在定義函數時就已經固定住了,不會隨著調用位置的改變而改變

 1 例一:
 2 name=yyp
 3 
 4 def foo():
 5     name=sy
 6     def bar():
 7         print(name)
 8     return bar
 9 
10 func=foo()
11 func()
12 
13 
14 例二:
15 name=yyp
16 
17 def foo():
18     name=sy
19     def bar():
20         name=tom
21         def tt():
22             print(name)
23         return tt
24     return bar
25 
26 func=foo()
27 func()()

九 遞歸調用

 1 def calc(n):
 2     print(n)
 3     if int(n/2) ==0:
 4         return n
 5     return calc(int(n/2))
 6  
 7 calc(10)
 8  
 9 輸出:
10 10
11 5
12 2
13 1
技術分享
 1 #_*_coding:utf-8_*_
 2 __author__ = Linhaifeng
 3 import time
 4 
 5 person_list=[alex,wupeiqi,yuanhao,linhaifeng]
 6 def ask_way(person_list):
 7     print(-*60)
 8     if len(person_list) == 0:
 9         return 沒人知道
10     person=person_list.pop(0)
11     if person == linhaifeng:
12         return %s說:我知道,老男孩就在沙河匯德商廈,下地鐵就是 %person
13     print(hi 美男[%s],敢問路在何方 %person)
14     print(%s回答道:我不知道,但念你慧眼識豬,你等著,我幫你問問%s... %(person,person_list))
15     time.sleep(3)
16     res=ask_way(person_list)
17     # print(‘%s問的結果是: %res‘ %(person,res))
18     return res
19 
20 
21 
22 res=ask_way(person_list)
23 
24 print(res)
遞歸問路

遞歸特性:

1. 必須有一個明確的結束條件

2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少

3. 遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)

鏈接:堆棧掃盲

技術分享
 1 data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
 2  
 3  
 4 def binary_search(dataset,find_num):
 5     print(dataset)
 6  
 7     if len(dataset) >1:
 8         mid = int(len(dataset)/2)
 9         if dataset[mid] == find_num:  #find it
10             print("找到數字",dataset[mid])
11         elif dataset[mid] > find_num :# 找的數在mid左面
12             print("\033[31;1m找的數在mid[%s]左面\033[0m" % dataset[mid])
13             return binary_search(dataset[0:mid], find_num)
14         else:# 找的數在mid右面
15             print("\033[32;1m找的數在mid[%s]右面\033[0m" % dataset[mid])
16             return binary_search(dataset[mid+1:],find_num)
17     else:
18         if dataset[0] == find_num:  #find it
19             print("找到數字啦",dataset[0])
20         else:
21             print("沒的分了,要找的數字[%s]不在列表裏" % find_num)
22  
23  
24 binary_search(data,66)
二分查找

十 匿名函數

匿名函數就是不需要顯式的指定函數

1 #這段代碼
2 def calc(n):
3     return n**n
4 print(calc(10))
5  
6 #換成匿名函數
7 calc = lambda n:n**n
8 print(calc(10))

匿名函數主要是和其它函數搭配使用的呢,如下

1 l=[3,2,100,999,213,1111,31121,333]
2 print(max(l))
3 
4 dic={k1:10,k2:100,k3:30}
5 
6 
7 print(max(dic))
8 print(dic[max(dic,key=lambda k:dic[k])])
 1 res = map(lambda x:x**2,[1,5,7,4,8])
 2 for i in res:
 3     print(i)
 4 
 5 輸出
 6 1
 7 25
 8 49
 9 16
10 64

十一 函數式編程

函數式編程:

http://egon09.blog.51cto.com/9161406/1842475

11 高階函數

滿足倆個特性任意一個即為高階函數

1.函數的傳入參數是一個函數名

2.函數的返回值是一個函數名

技術分享
 1 array=[1,3,4,71,2]
 2 
 3 ret=[]
 4 for i in array:
 5     ret.append(i**2)
 6 print(ret)
 7 
 8 #如果我們有一萬個列表,那麽你只能把上面的邏輯定義成函數
 9 def map_test(array):
10     ret=[]
11     for i in array:
12         ret.append(i**2)
13     return ret
14 
15 print(map_test(array))
16 
17 #如果我們的需求變了,不是把列表中每個元素都平方,還有加1,減一,那麽可以這樣
18 def add_num(x):
19     return x+1
20 def map_test(func,array):
21     ret=[]
22     for i in array:
23         ret.append(func(i))
24     return ret
25 
26 print(map_test(add_num,array))
27 #可以使用匿名函數
28 print(map_test(lambda x:x-1,array))
29 
30 
31 #上面就是map函數的功能,map得到的結果是可叠代對象
32 print(map(lambda x:x-1,range(5)))
map函數 技術分享
from functools import reduce
#合並,得一個合並的結果
array_test=[1,2,3,4,5,6,7]
array=range(100)

#報錯啊,res沒有指定初始值
def reduce_test(func,array):
    l=list(array)
    for i in l:
        res=func(res,i)
    return res

# print(reduce_test(lambda x,y:x+y,array))

#可以從列表左邊彈出第一個值
def reduce_test(func,array):
    l=list(array)
    res=l.pop(0)
    for i in l:
        res=func(res,i)
    return res

print(reduce_test(lambda x,y:x+y,array))

#我們應該支持用戶自己傳入初始值
def reduce_test(func,array,init=None):
    l=list(array)
    if init is None:
        res=l.pop(0)
    else:
        res=init
    for i in l:
        res=func(res,i)
    return res

print(reduce_test(lambda x,y:x+y,array))
print(reduce_test(lambda x,y:x+y,array,50))
reduce函數 技術分享
 1 #電影院聚集了一群看電影bb的傻逼,讓我們找出他們
 2 movie_people=[alex,wupeiqi,yuanhao,sb_alex,sb_wupeiqi,sb_yuanhao]
 3 
 4 def tell_sb(x):
 5     return x.startswith(sb)
 6 
 7 
 8 def filter_test(func,array):
 9     ret=[]
10     for i in array:
11         if func(i):
12             ret.append(i)
13     return ret
14 
15 print(filter_test(tell_sb,movie_people))
16 
17 
18 #函數filter,返回可叠代對象
19 print(filter(lambda x:x.startswith(sb),movie_people))
filter函數 技術分享
 1 #當然了,map,filter,reduce,可以處理所有數據類型
 2 
 3 name_dic=[
 4     {name:alex,age:1000},
 5     {name:wupeiqi,age:10000},
 6     {name:yuanhao,age:9000},
 7     {name:linhaifeng,age:18},
 8 ]
 9 #利用filter過濾掉千年王八,萬年龜,還有一個九千歲
10 def func(x):
11     age_list=[1000,10000,9000]
12     return x[age] not in age_list
13 
14 
15 res=filter(func,name_dic)
16 for i in res:
17     print(i)
18 
19 res=filter(lambda x:x[age] == 18,name_dic)
20 for i in res:
21     print(i)
22 
23 
24 #reduce用來計算1到100的和
25 from functools import reduce
26 print(reduce(lambda x,y:x+y,range(100),100))
27 print(reduce(lambda x,y:x+y,range(1,101)))
28 
29 #用map來處理字符串列表啊,把列表中所有人都變成sb,比方alex_sb
30 name=[alex,wupeiqi,yuanhao]
31 
32 res=map(lambda x:x+_sb,name)
33 for i in res:
34     print(i)
總結

十二 內置函數

技術分享

技術分享
 1 字典的運算:最小值,最大值,排序
 2 salaries={
 3     egon:3000,
 4     alex:100000000,
 5     wupeiqi:10000,
 6     yuanhao:2000
 7 }
 8 
 9 叠代字典,取得是key,因而比較的是key的最大和最小值
10 >>> max(salaries)
11 yuanhao
12 >>> min(salaries)
13 alex
14 
15 可以取values,來比較
16 >>> max(salaries.values())
17 >>> min(salaries.values())
18 但通常我們都是想取出,工資最高的那個人名,即比較的是salaries的值,得到的是鍵
19 >>> max(salaries,key=lambda k:salary[k])
20 alex
21 >>> min(salaries,key=lambda k:salary[k])
22 yuanhao
23 
24 
25 
26 也可以通過zip的方式實現
27 salaries_and_names=zip(salaries.values(),salaries.keys()) 
28 
29 先比較值,值相同則比較鍵
30 >>> max(salaries_and_names)
31 (100000000, alex)
32 
33 
34 salaries_and_names是叠代器,因而只能訪問一次
35 >>> min(salaries_and_names)
36 Traceback (most recent call last):
37   File "<stdin>", line 1, in <module>
38 ValueError: min() arg is an empty sequence
39 
40 
41 
42 sorted(iterable,key=None,reverse=False)
View Code

Python學習之路6?函數,遞歸,內置函數