函數
函數 Python函數,由若干語句組成語句塊,函數名稱,參數列表構成,他是組織代碼的最小單元
函數的作用
結構化編程對代碼的最基本的封裝,一般按照 功能組織一段代碼 封裝的目的為了服用,減少代碼函數的分類
內建函數
函數庫
函數的定義、調用
def 函數名(參數列表)
函數體
return
函數名就是標識符,命名要求一樣
語句塊必須縮進,約定4個空格
Python的函數沒有return語句,隱式會返回一個None值 定義中的參數列表成為形式參數,只是一種符號表達,簡稱形參
調用
調用的方式,就是函數名加上小括號,括號內寫上參數
調用時寫的參數是實際參數,是實實在在傳入的值,簡稱實參
函數是可調用的對象 callable() 函數返回 True False.
函數的參數
位置參數:按照參數定義順序傳入實參
關鍵字參數:使用形參的名字來出入實參的方式,如果使用來了形參名字,那么傳參順序就可和定義順序不同
可變參數:一個形參可以匹配任意個參數(傳入一個可迭代對象)
可變參數:在形參前使用*表示形參是可變參數,可以接受多個實參 要求位置參數必須在關鍵參數之前傳入,位置參數是按照位置對應的
函數參數默認值
定義時,在形參后跟上一個值
作用:參數的默認值可以在未傳入足夠實參的時候,對沒有給定的參數復制為默認值 參數非常多的時候,并不需要用戶每次都輸入所有的參數,簡化函數調用
def add(x=5,y=6)
print(‘good’)
return x+y
關鍵字參數的可變參數
def showconfig(**kwargs):
for k,v in kwargs.items():
print(‘{}’..format(k,v))
形參前使用**符號,表示可以接受多個關鍵字參數
keyword-only參數
keyword-only參數是 python03加入的
如果一個星號參數后,或者一個位置可變參數后,出現普通參數,實際上已經不是普通的參數了,而是keyword-only參數
def fn(*arg,x):
print(x)
print(args)
函數參數規則
參數列表參數一般順序是,普通參數,缺省參數,可變位置參數、keyword-only參數、可變關鍵字參數
參數解構
def add(x,y):
retuen x+y
add(4,5)
t = (1,3)
add(*t)
參數解構,給函數提供實參的時候,可以在集合類型前使用*或**,把集合類型的結構解開,提取出所有元素作為函數的實參
非字典類型使用*解構成位置參數
字典類型使用**解構成關鍵字參數 提取出來的元素數目和參數的要求匹配,也要和參數的類型匹配
def add(x,y):
return x+y
d= {‘x’:5,’y’:6}
add(**d)
def ?add(*iterable):
result = 0
for x in iterable:
result += x? ? return result
# add([1,2,3])
add(*range(10))
函數的返回值
Python函數使用return語句返回”返回值”
所有函數都有返回值,如果沒有return語句,隱式調用 return None
return 語句并不一定是函數的語句塊的最后一句
一個函數可以存在多個return語句,但是只有一條可以被執行,如果沒有一條return語句被執行到,隱式調用return None
如果有必要,可以顯示調用 return None,可以簡寫為 return
如果函數執行了return ,函數就會返回,當前被執行的return語句之后的其他語句就不會被執行了 函數的作用:結束函數調用、返回值
返回多個值
def showlist():
pass
return 11452,5,5,5
showlist()
返回的類型是一個元組
def showlist():
pass
return 11452,5,5,5
showlist()
print(type(showlist()))
<class ‘tuple’>
返回值的解構
def showlist():
pass
return 1,2,3
x,y,z = showlist()
函數嵌套: 在一個函數中定義了另外一個函數
def outer():
def inner():
print(“inner”)
print(“outer”)
inner()
outer()
函數的作用域: 作用域:一個標識符的可見范圍,這就是標識符的作用域。一般常說的是變量的作用域 全局作用域:
在整個程序運行環境中都可見
局部作用域:在函數、類等內部可見
局部變量使用范圍不能超過起所在的局部作用域
def outer():
o = 66
def inner():
print(“inner {}”.format(o))
print(chr(o))? ? print(“outer {}”.format(o))
inner()
def outer1():
a = 65
def inner1():
a = 97
print(“inner1 {}”.format(a))
print(chr(a))
print(“outer1 {}”.format(a))
inner1()
outer1()
從函數嵌套結構例子看出:
外層變量作用域在內層作用域可見
內層作用域inner中,如果定義了 o=97 ,相當于當前作用域重新定義了一個新的變量o,但是這個o 并沒有覆蓋外層作用域 outer 中的 o
global 使用原則
外部作用域變量會使內部作用域可見,但也不要在這個內部的局部作用域中直接使用,因為函數的目的就是為了封裝,盡量與外界隔離 如果函數需要使用為外部全局變量,使用函數的形參傳參解決 一句話:不用global
閉包:
自由變量:未在本地作用域中定義的變量。
閉包:就是一個概念,出現在嵌套函數中,指的是 內層函數引用到了 外層函數的自由變量,就形成了閉包。
def counter():
def inc():
c[0] += 1
return c[0]
return incfoo = counter()
print(foo(), foo())
c = 100
print(foo())
這是 Python 2 中實現閉包的方式,Python3 還可以使用nonlocal關鍵字
def sounter():
sount = 1
def inc():
nonlocal sount
sount += 1
return sount
return inc
foo = sounter()
foo()
foo()
使用了 nonclocal 關鍵字,將變量標記為在上級的局部作用域中定義,但不能是全局作用中定義
默認值的作用域:
def foo1(xyz=[]):
xyz.append(1)
print(xyz)
return xyz
foo1()
foo1()
[1]
[1, 1]
[1, 1, 1]
[1, 1, 1]
函數也是對象,python把函數的默認值放在了屬性中,這個屬性就伴著這個函數對象的生命周期查看 foo._default_ 屬性
def foo1(xyz=[],u=’abc’,z=123):
xyz.append(1)
print(xyz)
return xyz
print(foo1(),id(foo1))
print(foo1.__defaults__)
print(foo1(),id(foo1))
print(foo1.__defaults__)
[1]
[1] 140235248505856
([1], ‘abc’, 123)
[1, 1]
[1, 1] 140235248505856
([1, 1], ‘abc’, 123)
函數地址沒變,就是說函數這個對象沒變,調用它,他的屬性__defaults__中使用元組保存所有默認值xyz 默認值是引用類型,引用類型的元素變動,并不是元組的變化
非引用的默認值例子:
def fo1(w,u=’qqq’,z=123):
u = ‘q999w’
z = 9999
print(w,u,z)
print(fo1.__defaults__)
fo1(‘magedu’)print
(fo1.__defaults__)
默認值的作用域:
函數體內不改變默認值。
如果使用缺省值None 就創建一個列表
如果傳入一個列表,就修改這個列表
def foo(xyz=None, u=’adf’, z=2222):
if xyz is None:
xyz = []
xyz.append(1)
print(xyz)
foo()
print(foo.__defaults__)
foo()
print(foo.__defaults__)
foo([10])print(foo.__defaults__)
foo([10,5,5,55])
print(foo.__defaults__)
第一種方法: 使用影子拷貝創建一個新的對象,永遠不能改變傳入的參數第
二種方法: 通過值的判斷就可以靈活的選擇創建或者修改傳入的參數,這種方式靈活,應用廣泛,
函數的銷毀:
全局函數銷毀
重新定義同名函數
del 語句刪除函數對象
程序結束時
局部函數銷毀
重新在上級作用域定義同名函數
del 語句刪除函數對象
上級作用域銷毀時
遞歸函數
函數的執行過程:
def foo1(b, b1=3):
print(‘foo1 called’,b,b1)
def foo2(c):
foo3(c)
print(‘foo2 called’,c)
def foo3(d):
print(‘foo3 called’,d)
def main():
print(‘main called’)
foo1(100,111)
foo2(200)
print(‘main ending’)
main()
遞歸 ?recursion
函數直接或間接調用自身就是 遞歸
遞歸需要有邊界條件,遞歸前進段,遞歸返回段
遞歸一定要有–邊界條件 當邊界條件不滿足的時候,遞歸前進 當邊界條件滿足的時候,遞歸返回
遞歸要求
遞歸一定要有退出條件,遞歸調用一定要執行到這個退出條件,沒有退出條件的遞歸調用,就是無限調用 遞歸調用的深度不宜過深
Python 對遞歸調用的深度做了限制,以保護解釋器
超過遞歸深度限制,拋出RecursionError:maxinum recursion depth exceeded ?超出最大深度 sys.getrecursionnlimit()
遞歸的性能:
循環稍微復雜一些,但是只要不是死循環,可以多次迭代直至算出結果
遞歸還有深度限制,如果遞歸復雜,函數反復壓棧,棧內存很快溢出了
間接遞歸:
間接遞歸,是通過別的函數調用了函數自身
如果構成循環遞歸是非常危險的,在代碼復雜的情況下,要用代碼的規范來避免遞歸調用的發生
遞歸總結:
遞歸是一種自然的表達,符合邏輯思維
遞歸相對運行效率低,每一次調用函數都要開辟棧幀
遞歸有深度限制,如果遞歸層次太深,函數反復壓棧,棧內存很快就溢出了
如果是有限次數的遞歸,可以使用遞歸調用,或者使用循環代替,循環代碼稍微復雜一些,但是只要不是死循環,可以多次迭代直至算出結果
絕大多數遞歸,都可以使用循環實現
即使代碼遞歸很簡潔,但是能不用則不用遞歸
匿名函數:
匿名函數,即沒有名字的函數
Python 借助Lambda 表達式構建匿名函數
格式:lambda 參數列表:表達式 lambda x:x**2
使用lambda關鍵字來定義匿名函數
參數列表不需要小括號
冒號是用來分割參數列表和表達式的
不需要return ,表達式的值,就是匿名函數返回值
lambda 表達式 只能寫在一行上,被稱為單行函數
用途:在高階函數傳參時,使用lambda表達式,往往能簡化代碼
生成器: 生成器指的是生成器對象,可以由生成器表達式得到,也可以使用yield關鍵字得到一個生成器函數,調用這個函數得到一個生成器對象
生成器函數:
函數體中包含yield語句的函數,返回生成器對象
生成器對象,是一個可迭代對象,是一個迭代器
生成器對象,是延遲計算、惰性求值的
def inc():
for i in range(5):
yield i
print(type(inc))
print(type(inc()))
x = inc()
print(type(x))
print(next(x))
print(next(x))
for m in x:
print(m, ‘*’)
for m in x:
print(m, ‘**’)
普通的函數調用fn(),函數會立即執行完畢,但是生成器函數可以使用next函數多次執行
生成器函數等價于生成器表達式,只不過生成器函數可以更加的復雜
生成器函數:
包含了yield語句的生成器函數生成生成器對象時,生成器函數的函數體不會立即執行
next(generator) 會從函數的當前位置向后執行到碰到第一個yield語句,彈出值,并暫停函數執行
再次調用next函數,和上一條一樣的處理過程
沒有多余的yield的語句能被執行,繼續調用next函數,會拋出Stpoiteration異常
生成器應用
協成coroutine
生成器的高級用法
比進程,線程輕量級
是在用戶空間調度函數的一種實現
Python3 asyncio 就是協成實現,已經加入到標準庫
Python3.5 使用async,await關鍵字直接源生支持協成
協成調度器實現思路了: 有兩個生成器A,B next(A)后,A執行到了yield語句暫停,然后去執行next(B),B執行到yield語句也暫停,然后在此調用next(A),再調用next(B),周而復始,就實現了調度效果
可以引入調度策略來實現切換的方式
協成是一種非搶占式的調度
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/87933