1. 程式人生 > >python函數(全局變量,局部變量,作用域,遞歸函數,高階函數,匿名函數)

python函數(全局變量,局部變量,作用域,遞歸函數,高階函數,匿名函數)

1-1 內置函數 info 結果類型 函數地址 iterable 二層 abs ret

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()

python函數(全局變量,局部變量,作用域,遞歸函數,高階函數,匿名函數)