本篇介紹什么是函數、函數的特性、函數的定義、函數的調用、以及函數的參數、以及關於全局變量和局部變量的使用等等。
一、什么是函數:
函數是最基本的一種代碼抽象方式,為了實現某種特定的功能而組織的帶名字的代碼塊。
那為什么要使用函數呢?
1、避免代碼的重復性,即函數的可以重復使用的。
2、保持代碼的一致性,易於修改。即當函數被定義好,即可在很多地方為了實現相同或者相似的功能時可調用函數,而當這些功能發生改變時,我們只需修改該函數即可,不必麻煩的去修改每一處實現該功能的代碼。
3、擴展性。
其實簡單的來說:函數就行一個有着特定功能作用的工具,例如錘子或者扳手等,每當我們需要使用這些工具的時候,我們不需要臨時請師傅制作這樣一件工具,這樣將會十分繁瑣且消耗大量的時間,故我們僅需花費一定的代價去借用這些工具即可這些代價我們暫且可以把其稱之為參數,而造這些工具的人為了怕別人不知道這些工具的使用,通常會給這些工具貼上使用說明(函數說明),而制作這些工具也會使用許多材料結構即(函數體),當然一件工具會有命名即(函數名),而當我們使用工具完成后會獲得一些效果,我們也可以將這些效果稱為(返回值)。當然有工具自然會有工具箱即(類)。 |
二、函數的定義:
定義一個函數要使用 def 語句,依次寫出函數名、括號、括號中的參數和冒號:,然后,在縮進塊中編寫函數說明,函數體,函數的返回值用 return 語句返回。
def 函數名(參數1,參數2,參數3,......): """ 函數說明 """ 函數體 return 返回值
例如:
#定義一個獲取平方值的函數
def calc(x): """ :param x: 輸入數字 :return: 獲取該數字的返回值 """ res =x**2
return res #獲取返回值
res = calc(10) print(res)
注意:函數體內部的語句在執行時,一旦執行到return時,函數就執行完畢,即函數內return后面代碼將無效,並將結果返回。如果沒有return語句的函數,很多時候將其稱為過程,但其實默認返回None。
函數的定義通常類似於變量的定義,定義一個函數只給了函數一個名稱,指定了函數里包含的參數,和代碼塊結構。與變量類似,函數的定義也相當於將代碼塊以一種特定的方式存儲在內存中,只有當調用的時候才會執行,而當我們打印函數名時,其實打印的是內存地址;當打印函數名加括號時,則是返回值。例:
def greater(name): print("hello world,%s !"%name) return name greater("amanda") #調用函數,執行函數
print(greater) #打印函數地址
print(greater("amanda")) #調用函數,並且獲取返回值
#輸出為: #hello world,amanda ! #<function greater at 0x00000241C37A3E18> #hello world,amanda ! #amanda
當調用函數時,需傳入指定類型的參數,才會執行函數體中的代碼塊。
三、函數的參數:
3.1 形參和實參
形參即形式參數,函數完成其工作時所需的一項信息。形參不占用內存空間,只有在被調用時才會占用內存空間,調用完了即被釋放。
實參即實際參數,調用函數時傳給函數的信息。例如:
#形參和實參
def greater(name): #name即為形參
print("hello world,%s !"%name) return name greater("amanda") #Amanda即為實參
上述而言:在調用函數並傳入參數即greater("Amanda"),將實參"Amanda"傳遞給函數greater(),這個值就被存儲在形參name中。
3.2 位置參數和關鍵字參數
位置參數--> 在調用函數時,Python必須將每個實參都關聯到函數定義的一個形參中,最簡單的關聯方式就是基於實參的順序,這種方式即為位置實參。
關鍵字參數 --> 傳遞給函數的是鍵值對。由於在實參中的將名稱和值關聯起來,所以在傳入時無需考慮順序。

#位置參數,一一對應,不可多也不可少 def introduction(name,age,hobby): intro ="My name is %s,I'm %d years old,my hobby is %s."%(name,age,hobby) print(intro) introduction("Amanda",23,"eating")

#關鍵字參數,無需一一對應,但也不可多不可少 def introduction(name,age,hobby): intro ="My name is %s,I'm %d years old,my hobby is %s."%(name,age,hobby) print(intro) introduction(age=22,name="little-five",hobby="dancing")
但位置參數和關鍵字參數混合使用時:
1、位置參數必須寫在關鍵字參數的左邊
2、同一個參數不能兩次或者多次傳值,只能傳一次

#位置參數和關鍵字參數混合使用 def introduction(name,age,hobby): intro ="My name is %s,I'm %d years old,my hobby is %s."%(name,age,hobby) print(intro) introduction("Amanda",age="23",hobby="eating") #位置參數必須寫在關鍵字參數左邊 #introduction(name="Amanda",23,hobby="eating") #同一個參數傳值只能一次 #introduction("Amanda",23,age="eating")
注:在沒有參數組的情況下,傳入的值必須與形參的數量一致。
3.2 默認參數
定義函數時我們可以給參數傳遞默認值,當調用函數時沒有傳遞該參數值時使用默認參數值。帶默認值的參數稱為默認參數,而無默認值的參數為必需參數,調用函數時必需參數必填,默認參數選填。例如:
#默認參數 def introduction(name,age,hobby="runing"): intro ="My name is %s,I'm %d years old,my hobby is %s."%(name,age,hobby) print(intro) #當不給默認參數傳值時,默認使用默認參數值 introduction("Amanda",23) #而給默認參數傳值時,則覆蓋 introduction("Amanda",age=23,hobby="eating")
3.4 參數組
*args -->傳入的多余的位置參數,被args接收。即當要想傳入多於形參的實參,並且以位置參數的方式傳入,多於的參數其以元組的形式接收。

def calc(x,y,*args): res =x+y # print(x,y) print(x,y,args)#*args-->多於的參數,位置參數傳入,以元組的形式接收 return res calc(1,2,7,8,6) calc(2,3,{"name":"alex"}) #即使傳入字典,字典當成整體也會以元組的方式被接收 calc(3,4,["alex","James"],"hello world") calc(3,4,*["alex","James"]) #相當於該列表遍歷,逐個添加至列表並且轉為元組 calc(3,4,*"alex") #輸出為: #1 2 (7, 8, 6) #2 3 ({'name': 'alex'},) #3 4 (['alex', 'James'], 'hello world') #3 4 ('alex', 'James') #3 4 ('a', 'l', 'e', 'x')
**kwargs -->傳入的多余的關鍵字參數,被kwargs接收。即要想傳入多於形參的實參,並且以關鍵字參數的形式傳入,多於的參數其以字典的形式接收

# def calc(x,y,**kwargs): res =x+y #print(x,y) print(x,y,kwargs)#**kwargs-->多於的參數,位置參數傳入,以字典的形式接收 return res calc(x=1,y=3,name="alex") calc(1,2,**{"name":"Amanda"}) #輸出為: #1 3 {'name': 'alex'} #1 2 {'name': 'Amanda'}
當在函數值定義參數時,同時定義*args、**kwargs時,可以傳入任何參數。多余的位置參數,傳入函數,以元組的方式被存儲在*args中;而多余的關鍵字參數,傳入函數,以字典的方式被存儲在**kwargs中。
def calc(x,y,*args,**kwargs): res =x+y print(x,y,args,kwargs)#*args,**kwargs-->可以傳入任何參數
return res calc(1,23,"222",["Amanda","little-five"],greater="hello world") #輸出為: #1 23 ('222', ['Amanda', 'little-five']) {'greater': 'hello world'}
四、函數的作用域
這里我們需要簡單的了解以下關於變量的作用域有哪幾種?
L:local,局部作用域,即函數中定義的變量。 E: enclosing,嵌套父級函數的局部作用域,即包含此函數的上級的局部作用域,但不是全局的; G: global,全局變量,就是模塊級別定義的變量。 B: built-in,系統固定模塊里面的變量,比如 int,bytearray等。 搜索變量的優先級順序依次為: 局部作用域 >外層作用域 >當前模塊中的全局作用域 > python內置作用域,也就是 LEGB |
通過以下代碼或許我們可以更好的理解這四種作用域之間的關系:
1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3
4 x =int(1) #python內置作用域---->B
5 y =2 #當前模塊中的全局變量--->G
6 def outfunc(): 7 outpara = 3 #外層作用域 --->E
8 def infunc(): 9 inpara =4 #局部作用域 --->L
10 print(inpara) 11 infunc() 12 outfunc()
同時我們需要知道的是,函數中變量的作用域只與函數的聲明有關,而與函數的調用位置無關。通過下面這個例子我們可以知曉:
#函數名-->函數內存地址;函數名()-->執行函數,並且獲取返回值
name ="zhangsan"
def foo(): name ="lisi"
def bar(): name = "wangwu"
def mitt(): print(name) return mitt return bar foo()()() #相當於--------------- # bar =foo() #執行foo函數,並且獲取bar函數內存地址,並且賦值給bar變量 # mitt =bar() #bar內存地址加括號->執行bar函數,並且獲取mitt內存地址 # mitt() #mitt內存地址+括號-->執行mitt函數
#輸出結果為:wangwu 而不是zhangsan
這個結果為wangwu而不是zhangsan,則說明函數中變量的作用域只有函數的聲明有關,而與函數的調用位置無關。否則,輸出肯定為->zhangsan,因為若簡單的調用mitt()其變量為 name=”zhangsan“,則打印的為zhangsan。
五、全局變量和局部變量:
在函數外,一段代碼最開始所賦值的變量,其可以被多個函數所調用,其作用域為全局作用域,則稱為全局變量。
在函數內定義的變量名,只能在該函數內部引用,不能在函數外部引用這個變量名,其作用域為局部作用域,則稱為局部變量。例如:

name ="Amanda" #全局變量 def foo(): name ="zhangsan" print(name) def bar(): name ="lisi" #局部變量 print(name) bar() print(name) foo() #輸出結果: # Amanda # zhangsan # lisi
global -->若想在函數內部修改全局變量,則需要使用global關鍵

#注:global必須寫在全局變量修改前 name ="Amanda" #全局變量 def foo(): name ="zhangsan" print(name) def bar(): global name #修改的為全局變量 name ="lisi" #局部變量 print(name) bar() print(name) #函數沒有執行前,故打印的還是原局部變量name foo() #執行函數 print(name) #函數執行后,修改了全局變量為name =lisi
nonlocal -->若子函數內想修改父級函數的變量,則需要使用 nonlocal 鍵字

name ="Amanda" #全局變量 def foo(): name ="zhangsan" print(name) def bar(): nonlocal name name ="lisi" #局部變量 print(name) bar() print(name) #由於函數沒有調用前,函數沒有執行,故打印的還是Amanda foo() #函數執行 print(name) #函數執行后,由於nonlocal關鍵字,修改的僅是父級的變量name
注:無論是global還是nonlocal,都必須寫在變量的修改的前面。否則會報錯。