函數

函數,函數參數,參數解構,作用域,遞歸函數,匿名函數以及生成器的基本概念。

函數

函數 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

(0)
5220367552203675
上一篇 2017-10-17 09:15
下一篇 2017-10-17 20:33

相關推薦

  • Python函數式編程指南(四):生成器

    生成器是迭代器,同時也并不僅僅是迭代器,不過迭代器之外的用途實在是不多,所以我們可以大聲地說:生成器提供了非常方便的自定義迭代器的途徑。 這是函數式編程指南的最后一篇,似乎拖了一個星期才寫好,嗯…… 轉載請注明原作者和原文地址:) 4. 生成器(generator) 4.1. 生成器簡介 首先請確信,生成器就是一種迭代器。生成器擁有next方法并且行為與迭代…

    Linux干貨 2015-03-11
  • enumerate用法和轉置矩陣求解、效率測試

    enumerate用法和轉置矩陣求解、效率測試

    2018-04-08
  • 函數的一些簡單筆記

    函數 數學定義:y=f(x),y是x的函數,x是自變量 Python函數: 1、有若干個語句組成的語句塊、函數名稱、參數列表構成,它是組織代碼的最小單元 2、完成一定的功能 函數的作用: 1、結構化編程對代碼的基本的封裝,一般按照功能組織一段代碼 2、封裝的目的為了復用,減少冗余代碼 3、代碼更加簡潔美觀、可讀易懂 函數的分類: 1、內建函數,如max()、…

    2017-10-15
  • python中 ‘is’ 和 ‘==’ 區別

    id –> 唯一身份標識符,?is比較的是id, ==比較的是value?

    2018-04-16
  • 函數

    函數 數學定義:y=f(x),y是x的函數,x是自變量 Python函數 有若干個語句塊,函數名稱,參數列表構成,它是組織代碼的最小單元 完成一定作用 函數的作用 結構化編程對代碼的最基本的封裝,一般按照功能組織一段代碼 封裝的目的為了復用,減少了冗余代碼 代碼更加簡潔美觀,更加易讀 函數的分類 內建函數,如max(),reversed()等 庫函數,如ma…

    2018-04-16
欧美性久久久久