函數的基本概述
在學習函數之前,一直遵循:面向過程編程,即:根據業務邏輯從上到下實現功能,可以思考一下如果有某個功能的代碼是在多個地方使用的是否可以只寫一次?此時的代碼該如何定義。先觀察以下的案例:
while True:
if cpu利用率 > 90%:
#發送郵件提醒
連接郵箱服務器
發送郵件
關閉連接
if 硬盤使用空間 > 90%:
#發送郵件提醒
連接郵箱服務器
發送郵件
關閉連接
if 內存占用 > 80%:
#發送郵件提醒
連接郵箱服務器
發送郵件
關閉連接
以上代碼中每個if條件語句下內容可以被提取出來公用 例:
def 發送郵件(內容)
#發送郵件提醒
連接郵箱服務器
發送郵件
關閉連接
while True:
if cpu利用率 > 90%:
發送郵件('CPU報警')
if 硬盤使用空間 > 90%:
發送郵件('硬盤報警')
if 內存占用 > 80%:
發送郵件('內存報警')
對於上述的兩種實現方式,第二次必然比第一次的重用性和可讀性要好,可以減少大量的代碼量,減少開發時間,一處定義,多處調用,其實這就是函數式編程
函數式編程的概念:
開發程序時,需要某塊代碼多次使用,但是為了提高編寫的效率以及代碼的重用,所以把具有獨立功能的代碼塊組織為一個小模塊,這就是函數
函數的定義和調用
<1>定義函數
定義函數的格式如下:
def 函數名():
代碼
demo:
# 定義一個函數,能夠完成打印信息的功能
def printInfo():
print '------------------------------------'
print ' 人生苦短,我用Python'
print '------------------------------------'
函數的定義主要有如下要點:
• def:表示函數的關鍵字 • 函數名:函數的名稱,調用時根據函數名調用函數
• 函數體:函數中進行一系列的邏輯計算或是該函數的功能內容。
• 參數:為函數體提供數據
• 返回值:當函數執行完畢后,可以給調用者返回數據。
<2>調用函數
定義了函數之后,就相當於有了一個具有某些功能的代碼,想要讓這些代碼能夠執行,需要調用它(注意在定義函數時里面的內容不會執行)
調用函數很簡單的,通過 函數名() 即可完成調用
demo:
# 定義完函數后,函數是不會自動執行的,需要調用它才可以
printInfo()
<3>函數的文檔說明
例:
>>> def test(a,b):
... "用來完成對2個數求和"
... print("%d"%(a+b))
...
>>>
>>> test(11,22)
33
執行,以下代碼
>>> help(test)
能夠看到test函數的相關說明
==============================================
Help on function test in module __main__:
test(a, b)
用來完成對2個數求和
(END)
=============================================
函數的參數-返回值
<1> 定義帶有參數的函數
示例如下:
def addnum(a, b):
c = a+b
print c
<2> 調用帶有參數的函數
以調用上面的add2num(a, b)函數為例:
def addnum(a, b):
c = a+b
print c
add2num(11, 22) #調用帶有參數的函數時,需要在小括號中,傳遞數據
小總結:
• 定義時小括號中的參數,用來接收參數用的,稱為 “形參”
• 調用時小括號中的參數,用來傳遞給函數用的,稱為 “實參”
ps:后面會有單獨一篇詳解函數參數的博客
<3> 帶有返回值的函數
如下示例:
def add2num(a, b):
c = a+b
return c
保存函數的返回值示例如下:
#定義函數
def add2num(a, b):
return a+b
#調用函數,順便保存函數的返回值
result = add2num(100,98)
#因為result已經保存了add2num的返回值,所以接下來就可以使用了
print result
結果:
198
在python中我們可以返回多個值
>>> def divid(a, b):
... shang = a//b
... yushu = a%b
... return shang, yushu
...
>>> sh, yu = divid(5, 2)
>>> sh
5
>>> yu
1
本質是利用了元組
函數根據有沒有參數,有沒有返回值,可以相互組合,一共有4種
• 無參數,無返回值
• 無參數,無返回值
• 有參數,無返回值
• 有參數,有返回值
<1>無參數,無返回值的函數
此類函數,不能接收參數,也沒有返回值,一般情況下,打印提示燈類似的功能,使用這類的函數
<2>無參數,有返回值的函數
此類函數,不能接收參數,但是可以返回某個數據,一般情況下,像采集數據,用此類函數
<3>有參數,無返回值的函數
此類函數,能接收參數,但不可以返回數據,一般情況下,對某些變量設置數據而不需結果時,用此類函數
<4>有參數,有返回值的函數
此類函數,不僅能接收參數,還可以返回某個數據,一般情況下,像數據處理並需要結果的應用,用此類函數
小總結
• 函數根據有沒有參數,有沒有返回值可以相互組合
• 定義函數時,是根據實際的功能需求來設計的,所以不同開發人員編寫的函數類型各不相同
• 一個函數到底有沒有返回值,就看有沒有return,因為只有return才可以返回數據
• 在開發中往往根據需求來設計函數需不需要返回值
• 函數中,可以有多個return語句,但是只要執行到一個return語句,那么就意味着這個函數的調用完成
• 一個程序當中函數的名字盡量不要重復,當函數名字重復時后面的會把前面的覆蓋掉(注意:也不要與變量名重復同樣會被覆蓋)
函數的嵌套
def testB():
print('---- testB start----')
print('這里是testB函數執行的代碼...(省略)...')
print('---- testB end----')
def testA():
print('---- testA start----')
testB()
print('---- testA end----')
調用
testA()
結果:
---- testA start----
---- testB start----
這里是testB函數執行的代碼...(省略)...
---- testB end----
---- testA end----
小總結:
• 一個函數里面又調用了另外一個函數,這就是所謂的函數嵌套調用
• 如果函數A中,調用了另外一個函數B,那么先把函數B中的任務都執行完畢之后才會回到上次 函數A執行的位置
函數嵌套的案例:
1. 寫一個函數求三個數的和
2. 寫一個函數求三個數的平均值
# 求3個數的和
def sum3Number(a,b,c):
return a+b+c # return 的后面可以是數值,也可是一個表達式
# 完成對3個數求平均值
def average3Number(a,b,c):
# 因為sum3Number函數已經完成了3個數的就和,所以只需調用即可
# 即把接收到的3個數,當做實參傳遞即可
sumResult = sum3Number(a,b,c)
aveResult = sumResult/3.0
return aveResult
# 調用函數,完成對3個數求平均值
result = average3Number(11,2,55)
print("average is %d"%result)
函數的局部變量、全局變量
局部變量
示例:
In [8]: def text1():
...: a = 200
...: print("text1----%d" %a)
...: print("修改后")
...: a = 300
...: print("text1----%d" %a)
...:
In [9]: def text2():
...: a = 400
...: print("text2-----%d" %a)
...:
In [10]: text1()
text1----200
修改后
text1----300
In [11]: text2()
text2-----400
總結
• 局部變量,就是在函數內部定義的變量
• 不同的函數,可以定義相同的名字的局部變量,但是各用個的不會產生影響
• 局部變量的作用,為了臨時保存數據需要在函數中定義變量來進行存儲,這就是它的作用
全局變量
概念:如果一個變量,既能在一個函數中使用,也能在其他的函數中使用,這樣的變量就是全局變量
示例:
# 定義全局變量
In [12]: a = 250
In [13]: def text1():
...: print("----text1----%d" %a)
...:
In [14]: def text2():
...: print("----text2----%d" %a)
...:
In [15]: text1()
----text1----250
In [16]: text2()
----text2----250
當局部變量和全局變量重名的時候:
In [23]: a = 250 # 全局變量
In [24]: def text1():
...: # 局部變量
...: a = 521
...: print("----text1----%d" %a)
...: # 局部變量
...: a = 666
...: print("----text1----%d" %a)
...:
In [25]: def text2():
...: print("----text2----%d" %a)
...:
In [26]: text1()
----text1----521
----text1----666
In [27]: text2()
----text2----250
In [28]:
總結:
• 在函數外邊定義的變量叫做全局變量
• 全局變量能夠在所有的函數中進行訪問
• 如果全局變量的名字和局部變量的名字相同,那么使用的是局部變量的,小技巧強龍不壓地頭蛇
在函數內部修改全局變量:
In [31]: a = 250
In [32]: def text1():
...: a = 520
...: print("----text1----%d" %a)
In [33]:
In [33]: def text2():
...: global a
...: a = 666
...: print("----text2----%d" %a)
...:
In [34]: # 沒有調用任何函數
In [35]: print(a)
250
In [36]: # 調用text1
In [37]: text1()
----text1----520
In [38]: # 再次打印---->
In [39]: print(a)
250
In [40]: # 發現值並沒有修改
In [41]: # 調用text2
In [42]: text2()
----text2----666
In [43]: # 再次打印a
In [44]: print(a)
666
In [45]: # 值已修改
總結:
• 如果在函數中修改全局變量,那么就需要使用global進行聲明,否則相當於在(在沒有傳參數的情況)在函數內部重新定義了一個相同變量的對象
對於 --可變類型的全局變量-和-不可變類型的全局變量-在函數內部修改的區別
ps:后面會有博客詳細說明可變類型與不可變類型的概念
示例:------->不可變類型:
In [46]: a = 6
In [47]: def demo():
...: a += 1
...: print(a)
...:
In [48]: demo()
錯誤信息:
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-48-00cf94af4371> in <module>()
----> 1 demo()
<ipython-input-47-6e1d5ad81f64> in demo()
1 def demo():
----> 2 a += 1
3 print(a)
4
UnboundLocalError: local variable 'a' referenced before assignment
--------------------------------------------------------------------------
注:顯然是不可以修改
------->可變類型:
In [49]: a = [1,]
In [50]:
In [50]: def demo():
...: a.append(2)
...: print(a)
...:
In [51]: demo()
[1, 2]
In [52]: a
Out[52]: [1, 2]
當調用函數時,在執行函數時在函數內部修改了列表的值--同時外部打印時也發生了變化。
總結:
○ 如果在函數中修改全局變量,那么就需要使用global進行聲明,否則出錯
○ 在函數中不使用global聲明全局變量時不能修改全局變量的本質是不能修改全局變量的指向,即不能將全局變量指向新的數據。
○ 對於不可變類型的全局變量來說,因其指向的數據不能修改,所以不使用global時無法修改全局變量。
○ 對於可變類型的全局變量來說,因其指向的數據可以修改,所以不使用global時也可修改全局變量。