1. 程式人生 > >python函式(全域性變數,區域性變數,作用域,遞迴函式,高階函式,匿名函式)

python函式(全域性變數,區域性變數,作用域,遞迴函式,高階函式,匿名函式)

 

1.1函式

1.1.1什麼是函式

函式就是程式實現模組化的基本單元,一般實現某一功能的集合。
函式名:就相當於是程式程式碼集合的名稱
引數:就是函式運算時需要參與運算的值被稱作為引數
函式體:程式的某個功能,進行一系列的邏輯運算
return 返回值:函式的返回值能表示函式的執行結果或執行狀態。

1.1.2函式的作用

  1.  函式是組織好的,可重複使用的,用來實現單一,或者相關功能的程式碼。
  2.  函式能夠提高應用的模組性,和程式碼的重複利用率

我們已近知道python提供了許多內建函式,比如print(),我們自已建立的函式稱為內建函式

1.1.3定義函式的語法

def 函式名(引數):
    函式體
    return  返回值內容

1.1.4函式定義規則

  1. 函式程式碼以def關鍵詞開頭,後接定義函式的名稱和圓括號,冒號():
  2. 函式內容以冒號":"開始,並且縮排
  3. 函式內容的第一行內容可選擇性使用文件字串---用來定義該函式的說明
  4. 函式的返回值: return  [返回值內容]  用於結束函式,返回一個值,表示程式執行的結果。
  5. 函式不帶return 預設返回None   返回值可以是任何型別的資料(數字,字串,函式,列表,元祖,字典等),也可以是一個表示式
  6. 函式引數:任何傳入引數和自變數必須放在圓括號中間,圓括號之間用於定義引數。

1.1.5函式呼叫

定義函式語法

def printinfo():
    print("hello world")
    return

呼叫函式

printinfo()
#函式執行結果
hello world

檢視函式返回值

print(printinfo())
#結果
hello world
None             #預設函式值返回類容

其他返回值示例

def printinfo():
    print
("hello world") return [111+222] print(printinfo()) #結果 hello world [333] #返回值內容

 

1.1.5函式引數

注:形參和實參(定義函式時,圓括號(引數)中的所有引數都是形式引數也稱為形參,呼叫函式中,圓括號(引數)中的引數稱為實際引數,也叫實參)

1)必須引數::

2)關鍵字引數:

3)預設引數:

4)可變引數(*args,**kwargs):

 1.必須引數:

從字面理解:必須要傳入引數

傳入的引數:與定義的形參順序一一對應

def stuinfo(name,age):
    print(name,age)
    return

#在不傳入引數
stuinfo()  #呼叫函式

#函式執行結果
TypeError: stuinfo() missing 2 required positional arguments: 'name' and 'age'
#報錯,提示型別錯誤,該函式,缺少兩個位置引數
不傳入引數
def stuinfo(name,age):
    print(name,age)
    return
stuinfo("zhangsan",18) 
#函式執行結果
zhangsan 18
傳入引數

 2.關鍵字引數

def stuinfo(name,age,hobby):
    print(name,age,hobby)
    return

#引數位置匹配,關鍵字引數,與形參的位置順序無關,
stuinfo(age=19,name="lisi",hobby="run")  
#name=   age=  hobby=就是關鍵字引數

#函式執行結果
lisi 19 run
關鍵字引數

3.預設引數

預設引數必須指向不變的物件

當函式有多個引數,把變化大的引數反正前面,變化小的引數放在後面。變化小的引數就作為預設引數。

預設引數好處:降低呼叫函式的難度

#預設引數,可以直接使用用,也可以修改預設引數值
def grade(name,age,city="BeiJing"):  #city="BeiJing"  就是預設引數
    print(name,age,city)
# grade("yangjian",age=18)
grade("lala",age=18,city="shanghai")

#grade函式執行結果
lala 18 shanghai
預設引數

4.可變引數

*args  **args

用途:在定義函式需要,每個定義函式功能的都可以繼續優化,所以我們需要用動態引數

如果把引數寫死了,後期繼續修改完善的功能的,修改該函式功能則會相當麻煩

*args  結果型別是元祖,傳遞值是任意型別

def test(*args):
    print(args)
test(123456,[12,45,88],{"name":"qw","age":15}) #可以傳遞任意引數的型別
#函式執行結果
(123456, [12, 45, 88], {'name': 'qw', 'age': 15})

**kwargs結果型別是字典,傳遞值是以key=value方式傳入

def test1(**kwargs):
    print(kwargs)
test1(name="xiha",age="12")

#執行結果
{'age': '12', 'name': 'xiha'}

 

函式* 和 ** 解包

#*
def test(*args):
    print(args)
test(*[1,2,3,4,5,6,7,8,9])  #*引數解包,把【元素】 迴圈出來,新增到元祖中
#結果
(1, 2, 3, 4, 5, 6, 7, 8, 9)
*
def test1(**kwargs):
    print(kwargs)
test1(**{"hobby":456,"number":789}) #**引數解包,把key:value 迴圈出來,新增到字典中
#結果
{'number': 789, 'hobby': 456}
**

 

函式引數組合

def f2(a, b, c=0,*args,**kwargs):
    print('a =', a, 'b =', b, 'c =', c, args,kwargs)
f2(12,b=12,c=89,aa="as",bb="xxx")
#結果
a = 12 b = 12 c = 89 () {'bb': 'xxx', 'aa': 'as'}

函式引數總結:

1.形參的位置順序,必須與實參的順序一一對應,缺一不行,多一不行

2.關鍵字引數,無須一一對應,缺一不行,多一不行

3.位置引數必須在關鍵字引數左邊

4.預設引數一定要用不可變物件,如果是可變物件,程式執行時會有邏輯錯誤

1.2全域性變數和區域性變數

在子程式中定義的變數稱為區域性變數,只在子程式內部生效,

在程式一開始定義的變數稱為全域性變數

全域性變數作用域是整個程式,區域性變數作用域是定義該變數的子程式。

當全域性變數與區域性變數同名時:在定義區域性變數的子程式內,區域性變數起作用,在其他地方全域性變數起作用

name = "xixi"   #全域性變數
def change_name():
    name = "haha"  #區域性變數只在函式區域性作用域內生效
    print("我的名字",name)
    return
change_name()
print(name)

def me():
    global name #宣告name是全域性變數  global
    name = "yj"  #修改name全域性變數的值
    print(name)
    return
me()

如果全域性變數是可變的資料型別,函式可以對全域性變數內部直接進行修改

eng = ["merry","jack","petter"]
def chang():
    eng.append("mali")
    print(eng)
    return
chang()

總結:

一般寫程式變數的命名規則

###全域性變數變數名大寫

###區域性變數變數名小寫

  1. 函式優先讀取區域性變數,能讀全域性變數,無法對全域性變數重新賦值操作,#全域性變數是不可變的型別
  2. 全域性變數是可變型別,函式可以對全域性變數進行操作
  3. 函式中有global關鍵字,變數本質就是全域性變數,可讀取全域性變數,也可操作全域性變數

1.3函式之間巢狀

 

name = "YangJIan"  #最外層

def change_name(): #第二層
    name = "YangJIan2"

    def change_name2(): #第三層
        name = "YangJIan3"
        print("第3層列印", name)
        
    change_name2()  # 呼叫內層函式
    print("第2層列印", name)
change_name()  #先執行區域性函式的列印,
print("最外層列印", name)

# 第3層列印 YangJIan3
# 第2層列印 YangJIan2
# 最外層列印 YangJIan

注:多層函式巢狀,子級函式,只在子級函式內部生效。父級函式能呼叫子級函式的功能

1.4遞迴函式

1.在函式內部,可以呼叫其他函式,如果一個函式在內部呼叫自身本身,這個函式就是遞迴函式。

2.在使用遞迴策越是,必須有一個明確的敵對結束條件,稱為遞迴出口

函式呼叫的時候,每次呼叫時要做地址儲存,引數傳遞等。

 

如果函式包含了對其自身函式的呼叫,該函式就是遞迴。如下

def foo(n):
    #實現階乘
    if  n == 1:
        return n  # 當滿種條件n==1才執行return 操作
    res = n*foo(n-1) #呼叫自已本身的函式的結果(再判斷條件是否滿足條件)給res ,
    return res
print(foo(5))
#120

 遞迴演算法所所體現的重複一般有的要求:

1.每次呼叫在上次規模上都有有所減小:

2.每次遞迴呼叫都是有明確條件的。

3.相領兩次的重複之間有緊密的聯絡,前一次要為後一次做準備(通常前一次的輸出(返回值結果))就作為後一次的輸入;

4.在問題的規模得到滿足條件時,而不再進行遞迴呼叫。

1.5函數語言程式設計

面向過程程式設計:我們通過把大段程式碼拆成函式,通過一層一層的函式,可以把複雜的任務分解成簡單的任務,這種一步一步的分解可以稱之為面向過程的程式設計。函式就是面向過程的程式設計的基本單元。

函數語言程式設計:是使用一系列函式去解決問題,函數語言程式設計就是根據程式設計的正規化來的出想要的結果,只要是輸入時確定的,輸出就是確定的。

1.6高階函式

能把函式作為引數傳入,這樣的函式就稱為高階函式。

回到頂部

1.6.1函式即變數

以python的內建函式print()為列,呼叫該函式一下程式碼

>>> print("hello world")
hello world

#只寫print
>>> print
<built-in function print>

#可見print("hello world")是函式呼叫,而print是函式本身

要獲得函式呼叫執行的結果,我們把結果賦值給變數:

>>> aa = abs(-20)
>>> aa
20

如果把函式本身賦值給變數

>>> p = print
>>> p
<built-in function print>

#函式本身可以賦值給變數,變數可以指向函式

我們通過變數來呼叫這個print函式,驗證結果如下

>>> p("check")
check

總結:函式名也是變數,對於print()這個內建函式,完全可以把函式名print看成變數,它指向一個可以列印任何東西的函式

注:實際程式程式碼絕不能這麼寫,上面只是為了舉例說明,要恢復print函式,請重啟python的互動環境

回到頂部

1.6.2傳入函式

變數可以指向函式,函式的引數能接收變數,那麼一個函式就可以接收另一函式作為函式,這種函式就稱為高階函式,

函式的返回值是一個函式名,也是高階函式。

例如:一個簡單的高階函式

def add(x,y,z):
    return abs(x)+abs(y)
aa = add(12,23,abs)   #函式執行的結果 賦值給 aa
print(aa) #檢視aa的值
#35 

#注,abs()函式是求一個整數的絕對值

1.7匿名函式

什麼是匿名函式:

在python中有一個匿名函式lambda,匿名函式就是指:無需定義識別符號(函式名)的函式或子程式。

定義lambda表示式:

lambda  arguments:express    

#arguments 引數(可以有多個引數)
#express 表示式

#lambda返回值是一個函式的地址,也就是函式物件
aa = lambda  arguments:express  #把的到lambda函式地址,賦值給變數aa

檢視這個lambda函式地址   ,用aa(argument)   檢視這個函式的值

 

例1

def pf(x=0):
    return x**2
print(pf(3))
普通函式定義,求數字平方
aa = lambda x:x**2
print(aa(4))
#16
lambda函式,求數字平方

 總結:

1.lambda函式可以引數可以有多個,包含的表示式不能超過一個,不要試圖向lambda函式中塞入太多東西,如果你需要做複雜的功能,應該定義一個普通函式,想定義什麼就定義什麼。

2.lambda函式用在需要封裝特殊的,非重用程式碼上,避免令我們的程式碼充斥大量的單行函式。

map函式

map()函式,map對映  

map(func,iterable)

map()函式接受兩個引數,一個是函式,一個可迭代的物件(iterable),map將傳入的函式依次作用到序列的每個元素,並把結果作為新的 可迭代的物件 的結果返回

例:有個函式,f(x) = x+1 把得到的數字 加1    要把這個函式作用在一個[1,2,3,4,5,6]上

number = [1,2,3,4,5,6]
#1.用普通函式定義方法
def add_one(x):
    return x+1
def map_test(func,arrey):
    res = []
    for i in arrey:
        i = func(i)
        res.append(i)
    return res
print(map_test(add_one,number))
#[2, 3, 4, 5, 6, 7]


#2.用lambda函式定義的得到結果,藉助1定義的map_test函式
print(map_test(lambda x:x+1,number))
#[2, 3, 4, 5, 6, 7]

#3.用map()本身函式去定義
print(list(map(lambda x:x+1 ,number)))
#[2, 3, 4, 5, 6, 7]

#注:map()得出的結果是一個iterator ,需要用list()函式讓它個整個序列都計算出來返回一個list

我們可能會想,寫一個迴圈,也可以計算出結果,但要實現多個功能,是不是也要寫多個迴圈 例:得出每個列表中元素的平方或則n次方

map()作為高階函式,事實上把運算規則抽象了,不但可以計算簡單的 f(x) = x+1 ,也能計算更復雜的函式。

總結:map() 處理序列中的每個元素,得到的結果是一個 iterator ,需通過list(iteratro),該list元素個數,與原來位置一樣

reduce函式

在python2可以直接用reduce()函式

在python3需要呼叫reduce模組

from functools import reduce
reduce(function, sequence, initial=None)  #該函式的預設用法

reduce函式,將function作用sequence序列的元素,每次攜帶一對(先前的結果以及下一序列的元素),連續的將現有的結果和下一個作用在獲得的隨後的結果上,最後得到我們的序列為一個最終結果的返回值

number1 = [2,3,4,10]
#1.普通函式定義
def chengfa(x,y):
    return x*y  #返回得到兩個數相乘的結果
def reduce_test(func,seq,init=None):
    if init is None:
        res = seq.pop(0)   #seq刪除第一個元素,並獲取刪除這個元素 賦值給res
    else:
        res = init
    for i in seq:
        res = func(res,i)  #迴圈一次,執行func這個函式
    return res
print(reduce_test(chengfa,number1))
#240
print(reduce_test(chengfa,number1,10))
#2400

#如果給了init 初始值,就是從初始值 乘以列表的每個元素的的出結果

#2.lambda函式,藉助reduce_test()函式定義
print(reduce_test(lambda x,y:x*y,number1,init=3))
#720

#3.使用reduce(),結合lambda()
print(reduce(lambda x,y:x*y, number1))
#240

得到列表所有元素,相乘的結果

number1 = [2,3,4,10]
#1.普通函式定義
def chengfa(x,y):
    return x*y  #返回得到兩個數相乘的結果
def reduce_test(func,seq,init=None):
    if init is None:
        res = seq.pop(0)   #seq刪除第一個元素,並獲取刪除這個元素 賦值給res
    else:
        res = init
    for i in seq:
        res = func(res,i)  #迴圈一次,執行func這個函式
    return res
print(reduce_test(chengfa,number1))
#240
print(reduce_test(chengfa,number1,10))
#2400

#如果給了init 初始值,就是從初始值 乘以列表的每個元素的的出結果

#2.lambda函式,藉助reduce_test()函式定義
print(reduce_test(lambda x,y:x*y,number1,init=3))
#720

#3.使用reduce(),結合lambda()
from functools import reduce
print(reduce(lambda x,y:x*y, number1))
#240
得到列表所有元素,相乘的結果
print(reduce(lambda x,y:x+y,range(1,101)))
得到1-100的和

 

filter函式

filter()函式用於過濾序列

和map()類似,filter()也接受一個函式和一個序列(可迭代的物件,也就是能被for迴圈),和map()不同的是,fillter()把傳入的函式依次作用於每個元素,然後根據返回值是True還是False決定保留還是丟棄該元素。

例:

aa = ['A', '', 'B', None, 'C', '  ']
#1.自定義函式測試
def not_empty(s):
    return  s and s.strip()
def filter_test(func,iter):
    res = []
    for i in iter:
        i = func(i)
        if i:
            res.append(i)
    return res
print(filter_test(not_empty,aa))

#['A', 'B', 'C']

#2.filter內建函式測試
print(list(filter(not_empty,aa)))
#['A', 'B', 'C']
把列表中空字串,空元素,都去掉

filter()這個函式,關鍵在於正確實現一個篩選函式,

注:filter()函式返回的是一個iterator,記憶體地址,需要看記憶體地址的值, 用list()函式或得該地址的值 

sorted函式

sorted()函式也是一個高階函式,它可以接收key

sorted排序,排序是比較元素的大小,如果是數字可以直接比較,如果是字串或則兩個dict(字典)?

sorted()傳入的引數是可迭代的物件,返回值的物件是一個列表

例:

aa = [11,-10,20,21,30,-40]
print(sorted(aa))
數字預設排序

接收一個key函式來實現自定義排序

例:根據絕對值大小來進行排序

aa = [11,-10,20,21,30,-40]
print(sorted(aa,key=abs))
#[-10, 11, 20, 21, 30, -40]
根據絕對值排序

例:字串排序

print(sorted("hello"))
#['e', 'h', 'l', 'l', 'o']
print(sorted(["hello","ho","haha"]))
# ['haha', 'hello', 'ho']
字串排序

注:預設情況下,對字串排序是按照ASCII編碼表的大小進行比較的

 

最後總結:

python內建的幾個高階函式:map() ,reduce(),filter,sorted()

 

 

 

1.1函式

1.1.1什麼是函式

函式就是程式實現模組化的基本單元,一般實現某一功能的集合。
函式名:就相當於是程式程式碼集合的名稱
引數:就是函式運算時需要參與運算的值被稱作為引數
函式體:程式的某個功能,進行一系列的邏輯運算
return 返回值:函式的返回值能表示函式的執行結果或執行狀態。

1.1.2函式的作用

  1.  函式是組織好的,可重複使用的,用來實現單一,或者相關功能的程式碼。
  2.  函式能夠提高應用的模組性,和程式碼的重複利用率

我們已近知道python提供了許多內建函式,比如print(),我們自已建立的函式稱為內建函式

1.1.3定義函式的語法

def 函式名(引數):
    函式體
    return  返回值內容

1.1.4函式定義規則

  1. 函式程式碼以def關鍵詞開頭,後接定義函式的名稱和圓括號,冒號():
  2. 函式內容以冒號":"開始,並且縮排
  3. 函式內容的第一行內容可選擇性使用文件字串---用來定義該函式的說明
  4. 函式的返回值: return  [返回值內容]  用於結束函式,返回一個值,表示程式執行的結果。
  5. 函式不帶return 預設返回None   返回值可以是任何型別的資料(數字,字串,函式,列表,元祖,字典等),也可以是一個表示式
  6. 函式引數:任何傳入引數和自變數必須放在圓括號中間,圓括號之間用於定義引數。

1.1.5函式呼叫

定義函式語法

def printinfo():
    print("hello world")
    return

呼叫函式

printinfo()
#函式執行結果
hello world

檢視函式返回值

print(printinfo())
#結果
hello world
None             #預設函式值返回類容

其他返回值示例

def printinfo():
    print("hello world")
    return  [111+222]
print(printinfo())

#結果
hello world
[333]        #返回值內容

 

1.1.5函式引數

注:形參和實參(定義函式時,圓括號(引數)中的所有引數都是形式引數也稱為形參,呼叫函式中,圓括號(引數)中的引數稱為實際引數,也叫實參)

1)必須引數::

2)關鍵字引數:

3)預設引數:

4)可變引數(*args,**kwargs):

 1.必須引數:

從字面理解:必須要傳入引數

傳入的引數:與定義的形參順序一一對應

def stuinfo(name,age):
    print(name,age)
    return

#在不傳入引數
stuinfo()  #呼叫函式

#函式執行結果
TypeError: stuinfo() missing 2 required positional arguments: 'name' and 'age'
#報錯,提示型別錯誤,該函式,缺少兩個位置引數
不傳入引數
def stuinfo(name,age):
    print(name,age)
    return
stuinfo("zhangsan",18) 
#函式執行結果
zhangsan 18
傳入引數

 2.關鍵字引數

def stuinfo(name,age,hobby):
    print(name,age,hobby)
    return

#引數位置匹配,關鍵字引數,與形參的位置順序無關,
stuinfo(age=19,name="lisi",hobby="run")  
#name=   age=  hobby=就是關鍵字引數

#函式執行結果
lisi 19 run
關鍵字引數

3.預設引數

預設引數必須指向不變的物件

當函式有多個引數,把變化大的引數反正前面,變化小的引數放在後面。變化小的引數就作為預設引數。

預設引數好處:降低呼叫函式的難度

#預設引數,可以直接使用用,也可以修改預設引數值
def grade(name,age,city="BeiJing"):  #city="BeiJing"  就是預設引數
    print(name,age,city)
# grade("yangjian",age=18)
grade("lala",age=18,city="shanghai")

#grade函式執行結果
lala 18 shanghai
預設引數

4.可變引數

*args  **args

用途:在定義函式需要,每個定義函式功能的都可以繼續優化,所以我們需要用動態引數

如果把引數寫死了,後期繼續修改完善的功能的,修改該函式功能則會相當麻煩

*args  結果型別是元祖,傳遞值是任意型別

def test(*args):
    print(args)
test(123456,[12,45,88],{"name":"qw","age":15}) #可以傳遞任意引數的型別
#函式執行結果
(123456, [12, 45, 88], {'name': 'qw', 'age': 15})

**kwargs結果型別是字典,傳遞值是以key=value方式傳入

def test1(**kwargs):
    print(kwargs)
test1(name="xiha",age="12")

#執行結果
{'age': '12', 'name': 'xiha'}

 

函式* 和 ** 解包

#*
def test(*args):
    print(args)
test(*[1,2,3,4,5,6,7,8,9])  #*引數解包,把【元素】 迴圈出來,新增到元祖中
#結果
(1, 2, 3, 4, 5, 6, 7, 8, 9)
*
def test1(**kwargs):
    print(kwargs)
test1(**{"hobby":456,"number":789}) #**引數解包,把key:value 迴圈出來,新增到字典中
#結果
{'number': 789, 'hobby': 456}
**

 

函式引數組合

def f2(a, b, c=0,*args,**kwargs):
    print('a =', a, 'b =', b, 'c =', c, args,kwargs)
f2(12,b=12,c=89,aa="as",bb="xxx")
#結果
a = 12 b = 12 c = 89 () {'bb': 'xxx', 'aa': 'as'}

函式引數總結:

1.形參的位置順序,必須與實參的順序一一對應,缺一不行,多一不行

2.關鍵字引數,無須一一對應,缺一不行,多一不行

3.位置引數必須在關鍵字引數左邊

4.預設引數一定要用不可變物件,如果是可變物件,程式執行時會有邏輯錯誤

1.2全域性變數和區域性變數

在子程式中定義的變數稱為區域性變數,只在子程式內部生效,

在程式一開始定義的變數稱為全域性變數

全域性變數作用域是整個程式,區域性變數作用域是定義該變數的子程式。

當全域性變數與區域性變數同名時:在定義區域性變數的子程式內,區域性變數起作用,在其他地方全域性變數起作用

name = "xixi"   #全域性變數
def change_name():
    name = "haha"  #區域性變數只在函式區域性作用域內生效
    print("我的名字",name)
    return
change_name()
print(name)

def me():
    global name #宣告name是全域性變數  global
    name = "yj"  #修改name全域性變數的值
    print(name)
    return
me()

如果全域性變數是可變的資料型別,函式可以對全域性變數內部直接進行修改

eng = ["merry","jack","petter"]
def chang():
    eng.append("mali")
    print(eng)
    return
chang()

總結:

一般寫程式變數的命名規則

###全域性變數變數名大寫

###區域性變數變數名小寫

  1. 函式優先讀取區域性變數,能讀全域性變數,無法對全域性變數重新賦值操作,#全域性變數是不可變的型別
  2. 全域性變數是可變型別,函式可以對全域性變數進行操作
  3. 函式中有global關鍵字,變數本質就是全域性變數,可讀取全域性變數,也可操作全域性變數

1.3函式之間巢狀

 

name = "YangJIan"  #最外層

def change_name(): #第二層
    name = "YangJIan2"

    def change_name2(): #第三層
        name = "YangJIan3"
        print("第3層列印", name)
        
    change_name2()  # 呼叫內層函式
    print("第2層列印", name)
change_name()  #先執行區域性函式的列印,
print("最外層列印", name)

# 第3層列印 YangJIan3
# 第2層列印 YangJIan2
# 最外層列印 YangJIan

注:多層函式巢狀,子級函式,只在子級函式內部生效。父級函式能呼叫子級函式的功能

1.4遞迴函式

1.在函式內部,可以呼叫其他函式,如果一個函式在內部呼叫自身本身,這個函式就是遞迴函式。

2.在使用遞迴策越是,必須有一個明確的敵對結束條件,稱為遞迴出口

函式呼叫的時候,每次呼叫時要做地址儲存,引數傳遞等。

 

如果函式包含了對其自身函式的呼叫,該函式就是遞迴。如下

def foo(n):
    #實現階乘
    if  n == 1:
        return n  # 當滿種條件n==1才執行return 操作
    res = n*foo(n-1) #呼叫自已本身的函式的結果(再判斷條件是否滿足條件)給res ,
    return res
print(foo(5))
#120

 遞迴演算法所所體現的重複一般有的要求:

1.每次呼叫在上次規模上都有有所減小:

2.每次遞迴呼叫都是有明確條件的。

3.相領兩次的重複之間有緊密的聯絡,前一次要為後一次做準備(通常前一次的輸出(返回值結果))就作為後一次的輸入;

4.在問題的規模得到滿足條件時,而不再進行遞迴呼叫。

1.5函數語言程式設計

面向過程程式設計:我們通過把大段程式碼拆成函式,通過一層一層的函式,可以把複雜的任務分解成簡單的任務,這種一步一步的分解可以稱之為面向過程的程式設計。函式就是面向過程的程式設計的基本單元。

函數語言程式設計:是使用一系列函式去解決問題,函數語言程式設計就是根據程式設計的正規化來的出想要的結果,只要是輸入時確定的,輸出就是確定的。

1.6高階函式

能把函式作為引數傳入,這樣的函式就稱為高階函式。

回到頂部

1.6.1函式即變數

以python的內建函式print()為列,呼叫該函式一下程式碼

>>> print("hello world")
hello world

#只寫print
>>> print
<built-in function print>

#可見print("hello world")是函式呼叫,而print是函式本身

要獲得函式呼叫執行的結果,我們把結果賦值給變數:

>>> aa = abs(-20)
>>> aa
20

如果把函式本身賦值給變數

>>> p = print
>>> p
<built-in function print>

#函式本身可以賦值給變數,變數可以指向函式

我們通過變數來呼叫這個print函式,驗證結果如下

>>> p("check")
check

總結:函式名也是變數,對於print()這個內建函式,完全可以把函式名print看成變數,它指向一個可以列印任何東西的函式

注:實際程式程式碼絕不能這麼寫,上面只是為了舉例說明,要恢復print函式,請重啟python的互動環境

回到頂部

1.6.2傳入函式

變數可以指向函式,函式的引數能接收變數,那麼一個函式就可以接收另一函式作為函式,這種函式就稱為高階函式,

函式的返回值是一個函式名,也是高階函式。

例如:一個簡單的高階函式

def add(x,y,z):
    return abs(x)+abs(y)
aa = add(12,23,abs)   #函式執行的結果 賦值給 aa
print(aa) #檢視aa的值
#35 

#注,abs()函式是求一個整數的絕對值

1.7匿名函式

什麼是匿名函式:

在python中有一個匿名函式lambda,匿名函式就是指:無需定義識別符號(函式名)的函式或子程式。

定義lambda表示式:

lambda  arguments:express    

#arguments 引數(可以有多個引數)
#express 表示式

#lambda返回值是一個函式的地址,也就是函式物件
aa = lambda  arguments:express  #把的到lambda函式地址,賦值給變數aa

檢視這個lambda函式地址   ,用aa(argument)   檢視這個函式的值

 

例1

def pf(x=0):
    return x**2
print(pf(3))
普通函式定義,求數字平方
aa = lambda x:x**2
print(aa(4))
#16
lambda函式,求數字平方

 總結:

1.lambda函式可以引數可以有多個,包含的表示式不能超過一個,不要試圖向lambda函式中塞入太多東西,如果你需要做複雜的功能,應該定義一個普通函式,想定義什麼就定義什麼。

2.lambda函式用在需要封裝特殊的,非重用程式碼上,避免令我們的程式碼充斥大量的單行函式。

map函式

map()函式,map對映  

map(func,iterable)

map()函式接受兩個引數,一個是函式,一個可迭代的物件(iterable),map將傳入的函式依次作用到序列的每個元素,並把結果作為新的 可迭代的物件 的結果返回

例:有個函式,f(x) = x+1 把得到的數字 加1    要把這個函式作用在一個[1,2,3,4,5,6]上

number = [1,2,3,4,5,6]
#1.用普通函式定義方法
def add_one(x):
    return x+1
def map_test(func,arrey):
    res = []
    for i in arrey:
        i = func(i)
        res.append(i)
    return res
print(map_test(add_one,number))
#[2, 3, 4, 5, 6, 7]


#2.用lambda函式定義的得到結果,藉助1定義的map_test函式
print(map_test(lambda x:x+1,number))
#[2, 3, 4, 5, 6, 7]

#3.用map()本身函式去定義
print(list(map(lambda x:x+1 ,number)))
#[2, 3, 4, 5, 6, 7]

#注:map()得出的結果是一個iterator ,需要用list()函式讓它個整個序列都計算出來返回一個list

我們可能會想,寫一個迴圈,也可以計算出結果,但要實現多個功能,是不是也要寫多個迴圈 例:得出每個列表中元素的平方或則n次方

map()作為高階函式,事實上把運算規則抽象了,不但可以計算簡單的 f(x) = x+1 ,也能計算更復雜的函式。

總結:map() 處理序列中的每個元素,得到的結果是一個 iterator ,需通過list(iteratro),該list元素個數,與原來位置一樣

reduce函式

在python2可以直接用reduce()函式

在python3需要呼叫reduce模組

from functools import reduce
reduce(function, sequence, initial=None)  #該函式的預設用法

reduce函式,將function作用sequence序列的元素,每次攜帶一對(先前的結果以及下一序列的元素),連續的將現有的結果和下一個作用在獲得的隨後的結果上,最後得到我們的序列為一個最終結果的返回值

number1 = [2,3,4,10]
#1.普通函式定義
def chengfa(x,y):
    return x*y  #返回得到兩個數相乘的結果
def reduce_test(func,seq,init=None):
    if init is None:
        res = seq.pop(0)   #seq刪除第一個元素,並獲取刪除這個元素 賦值給res
    else:
        res = init
    for i in seq:
        res = func(res,i)  #迴圈一次,執行func這個函式
    return res
print(reduce_test(chengfa,number1))
#240
print(reduce_test(chengfa,number1,10))
#2400

#如果給了init 初始值,就是從初始值 乘以列表的每個元素的的出結果

#2.lambda函式,藉助reduce_test()函式定義
print(reduce_test(lambda x,y:x*y,number1,init=3))
#720

#3.使用reduce(),結合lambda()
print(reduce(lambda x,y:x*y, number1))
#240

得到列表所有元素,相乘的結果

number1 = [2,3,4,10]
#1.普通函式定義
def chengfa(x,y):
    return x*y  #返回得到兩個數相乘的結果
def reduce_test(func,seq,init=None):
    if init is None:
        res = seq.pop(0)   #seq刪除第一個元素,並獲取刪除這個元素 賦值給res
    else:
        res = init
    for i in seq:
        res = func(res,i)  #迴圈一次,執行func這個函式
    return res
print(reduce_test(chengfa,number1))
#240
print(reduce_test(chengfa,number1,10))
#2400

#如果給了init 初始值,就是從初始值 乘以列表的每個元素的的出結果

#2.lambda函式,藉助reduce_test()函式定義
print(reduce_test(lambda x,y:x*y,number1,init=3))
#720

#3.使用reduce(),結合lambda()
from functools