一 函數是什麼?
函數一詞來源於數學,但編程中的「函數」概念,與數學中的函數是有很大不同的
函數能提高應用的模塊性,和代碼的重複利用率。你已經知道Python提供了許多內建函數,比如print()。
但你也可以自己創建函數,這被叫做用戶自定義函數。
定義: 函數是指將一組語句的集合通過一個名字(函數名)封裝起來,要想執行這個函數,只需調用其函數名即可
特性:
1.代碼重用
2.保持一致性
3.可擴展性
二 函數的創建
2.1 格式:
Python 定義函數使用 def 關鍵字,一般格式如下:
def 函數名(
參數列表):
函數體
>>> def hello():
>>> print('hello')
>>> hello() # 調用
2.2 函數名的命名規則:
函數名必須以下劃線或字母開頭,可以包含任意字母、數字或下劃線的組合。
不能使用任何的標點符號;
函數名是區分大小寫的。 #變量也是區分大小寫的
函數名不能是保留字。
2.3 形參和實參
形參:形式參數,不是實際存在,是虛擬變量。在定義函數和函數體的時候使用形參,目的是在函數調用時接收
實參(實參個數,類型應與實參一一對應)
實參:實際參數,調用函數時傳給函數的參數,可以是常量,變量,表達式,函數,傳給形參
區別:形參是虛擬的,不佔用內存空間,.形參變量只有在被調用時才分配內存單元,實參是一個變量,佔用內存
空間,數據傳送單向,實參傳給形參,不能形參傳給實參
>>> def add(a,b): # a b 是形參
>>> print(a+b)
>>> add(5,6) # 5 6 是形參
2.4 實例
>>> import time
>>> def logger(n):
>>> time_format='%Y-%m-%d %x'
>>> time_current=time.strftime(time_format)
>>> with open('日誌記錄', 'a') as f:
>>> f.write('%s end action%s\n' %(time_current, n))
>>> def action1(n):
>>> print ('starting action1...')
>>> logger(n)
>>> def action2(n):
>>> print ('starting action2...')
>>> logger(n)
>>> def action3(n):
>>> print ('starting action3...')
>>> logger(n)
>>> action1(1)
>>> action2(2)
>>> action3(3)
三 函數的參數
必備參數
關鍵字參數
默認參數
不定長參數
必備參數:
必備參數須以正確的順序傳入函數。調用時的數量必須和聲明時的一樣。
>>> def f(name,age):
>>> print('I am %s,I am %d'%(name,age))
>>> f('name',age) #位置一一對應
關鍵字參數:
關鍵字參數和函數調用關係緊密,函數調用使用關鍵字參數來確定傳入的參數值。使用關鍵字參數允許函數調用
時參數的順序與聲明時不一致,因爲 Python 解釋器能夠用參數名匹配參數值。
>>> def f(name,age):
>>> print('I am %s,I am %d'%(name,age))
>>> # f(16,'name') #會報錯
>>> f(age=16,name='name')
缺省參數(默認參數):
調用函數時,缺省參數的值如果沒有傳入,則被認爲是默認值。下例會打印默認的age,如果age沒有被傳入:
>>> def print_info(name,age,sex='male'):
>>> print('Name:%s'%name)
>>> print('age:%s'%age)
>>> print('Sex:%s'%sex)
>>> return
>>> print_info('alex',18)
>>> print_info('鐵錘',40,'female')
不定長參數
你可能需要一個函數能處理比當初聲明時更多的參數。這些參數叫做不定長參數,和上述2種參數不同,聲明時
不會命名。
>>> def add(*tuples):
>>> sum=0
>>> for v in tuples:
>>> sum+=v
>>> return sum
>>> print(add(1,4,6,9))
>>> print(add(1,4,6,9,5))
>>> def add(*t): # *t 等同於 上段代碼中的 *tuples 名字可以自定義
>>> print(type(t)) # <class 'tuple'> t個元組
>>> print(t) # (1, 4, 6, 9, 5)
>>> add(1,4,6,9,5)
加了星號(*)的變量名會存放所有未命名的變量參數。而加(**)的變量名會存放命名的變量參數
>>> def print_info(**kwargs):
>>> print(kwargs)
>>> for i in kwargs:
>>> print('%s:%s'%(i,kwargs[i])) #根據參數可以打印任意相關信息了
>>> return
>>> print_info(name='n',age=18,sex='female',hobby='girl')
輸出:
{'name': 'n', 'age': 18, 'sex': 'female', 'hobby': 'girl'}
name:n
age:18
sex:female
hobby:girl
>>> def print_info(**k): # **k 等同於 上段代碼中的 **kwargs 名字可以自定義
>>> print(type(k)) # <class 'dict'> # k是個字典
>>> print(k) # {'name': 'n', 'age': 18, 'sex': 'female', 'hobby': 'girl'}
>>> print_info(name='n',age=18,sex='female',hobby='girl')
關於不定長參數 *args 放左邊 **kwargs放右邊
形式如下
關鍵字參數 默認參數 *args **kwargs
def function(name,age=22,*args,**kwargs)
補充(高階函數):
高階函數是至少滿足下列一個條件的函數:
接受一個或多個函數作爲輸入
輸出一個函數
>>> def add(x,y,f):
>>> return f(x) + f(y)
>>> res = add(3,-6,abs) #abs爲其他函數
>>> print(res)
>>> def foo():
>>> x=3
>>> def bar():
>>> return x
>>> return bar
四 函數的返回值
要想獲取函數的執行結果,就可以用return語句把結果返回
注意:
函數在執行過程中只要遇到return語句,就會停止執行並返回結果, 也可以理解爲 return 語句代表着函數的結束
如果未在函數中指定return,那這個函數的返回值爲None
return多個對象,解釋器會把這多個對象組裝成一個元組作爲一個一個整體結果輸出。
五 作用域
5.1 作用域介紹
python中的作用域分4種情況:
L:local,局部作用域,即函數中定義的變量;
E:enclosing,嵌套的父級函數的局部作用域,即包含此函數的上級函數的局部作用域,但不是全局的;
G:globa,全局變量,就是模塊級別定義的變量;
B:built-in,系統固定模塊裏面的變量,比如int, bytearray等。
搜索變量的優先級順序依次是:作用域局部>外層作用域>當前模塊中的全局>python內置作用域,也就是LEGB。
>>> x = int(2.9) # int built-in
>>> g_count = 0 # global
>>> def outer():
>>> o_count = 1 # enclosing
>>> def inner():
>>> i_count = 2 # local
>>> print(o_count)
>>> # print(i_count) 超出作用於找不到
>>> inner()
>>> outer()
當然,local和enclosing是相對的,enclosing變量相對上層來說也是local。
5.2 作用域產生
在Python中,只有模塊(module),類(class)以及函數(def、lambda)纔會引入新的作用域,其它的代碼
塊(如if、try、for等)是不會引入新的作用域的,如下代碼:
>>> if 2>1:
>>> x = 1
>>> print(x) # 1
這個是沒有問題的,if並沒有引入一個新的作用域,x仍處在當前作用域中,後面代碼可以使用。
>>> def test():
>>> x = 2
>>> print(x) # NameError: name 'x2' is not defined
def、class、lambda是可以引入新作用域的。
5.3 變量的修改
>>> x=6
>>> def f2():
>>> print(x)
>>> x=5
>>> f2()
# 錯誤的原因在於print(x)時,解釋器會在局部作用域找,會找到x=5(函數已經加載到內存),但x使用在聲明前了,
所以報錯:
# local variable 'x' referenced before assignment.如何證明找到了x=5呢?簡單:註釋掉x=5,x=6
# 報錯爲:name 'x' is not defined
#同理
>>> x=6
>>> def f2():
>>> x+=1 #local variable 'x' referenced before assignment.
>>> f2()
5.4 global關鍵字
當內部作用域想修改外部作用域的變量時,就要用到global和nonlocal關鍵字了,
當修改的變量是在全局作用域(global作用域)上的,就要使用global先聲明一下,
代碼如下:
>>> count = 10
>>> def outer():
>>> global count
>>> print(count) #10
>>> count = 100
>>> print(count) #100
>>> outer()
5.5 nonlocal關鍵字
global關鍵字聲明的變量必須在全局作用域上,不能嵌套作用域上,當要修改嵌套作用域(enclosing作用域,
外層非全局作用域)中的變量怎麼辦呢,這時就需要nonlocal關鍵字了
>>> def outer():
>>> count = 10
>>> def inner():
>>> nonlocal count
>>> count = 20
>>> print(count) #20
>>> inner()
>>> print(count) #20
>>> outer()
5.6 小結
(1)變量查找順序:LEGB,作用域局部>外層作用域>當前模塊中的全局>python內置作用域;
(2)只有模塊、類、及函數才能引入新作用域;
(3)對於一個變量,內部作用域先聲明就會覆蓋外部變量,不聲明直接使用,就會使用外部作用域的變量;
(4)內部作用域要修改外部作用域變量的值時,全局變量要使用global關鍵字,嵌套作用域變量要使用nonlocal
關鍵字。nonlocal是python3新增的關鍵字,有了這個 關鍵字,就能完美的實現閉包了。
六 遞歸函數
定義:在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。
實例1(階乘)
>>> def factorial(n):
>>> result=n
>>> for i in range(1,n):
>>> result*=i
>>> return result
>>> print(factorial(4))
#**********遞歸*********
>>> def factorial_new(n):
>>> if n==1:
>>> return 1
>>> return n*factorial_new(n-1)
>>> print(factorial_new(3))
實例2(斐波那契數列)
>>> def fibo(n):
>>> before=0
>>> after=1
>>> for i in range(n-1):
>>> ret=before+after
>>> before=after
>>> after=ret
>>> return ret
>>> print(fibo(3))
#**************遞歸*********************
>>> def fibo_new(n):#n可以爲零,數列有[0]
>>> if n <= 1:
>>> return n
>>> return(fibo_new(n-1) + fibo_new(n-2))
>>> print(fibo_new(3)) #1
>>> print(fibo_new(30000)) #maximum recursion depth exceeded in comparison
遞歸函數的優點: 是定義簡單,邏輯清晰。理論上,所有的遞歸函數都可以寫成循環的方式,
但循環的邏輯不如遞歸清晰。
遞歸特性:
1. 必須有一個明確的結束條件
2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少
3. 遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,
每當進入一個函數調用,棧就會加一層棧幀,每當函數返 回,棧就會減一層棧幀。由於棧的大小不是無限的,
所以,遞歸調用的次數過多,會導致棧溢出。)
pythopn 函數
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.