一、函數介紹
1、函數是什麼?
函數一詞來源于數學,程式設計中的"函數"與數學中的函數有很大的不同。
(BASIC中叫subroutine,C中叫function,java中叫method)
定義:函數是指将一組語句的集合通過一個名字(函數名)封裝起來,想執行這個函數,隻需調用其函數名即可。
2、為什麼要使用函數?
(1)減少重複代碼:否則遇到重複的功能隻能重複編寫實作代碼,代碼備援
(2)使程式變得可擴充:否則功能需要擴充時,需要找出所有實作該功能的地方修改之,無法統一管理且維護難度極大
(3)使得程式變得易維護:否則代碼的組織結構不清晰,可讀性差
3、函數分類
(1)内置函數:針對一些簡單的功能,python解釋器已經為我們定義好了的函數即内置函數。對于内置函數,我們可以拿來就用而無需事先定義,如len(),sum(),max()。
(2)自定義函數:很明顯内置函數所能提供的功能是有限的,這就需要我們自己根據需求,事先定制好我們自己的函數來實作某種功能,以後,在遇到應用場景時,調用自定義的函數即可
二、函數的參數
參數的作用:可以讓函數更靈活,不隻能做死動作,還可以根據調用時傳參的不同來決定函數内部的執行流程。
# 無參函數
def sayhi(): # 函數名(小寫即可)
print("Hello,I'm nobody!")
sayhi() # 調用函數,函數名指向上述代碼指向的記憶體位置,加上括号才是執行代碼
print(sayhi) # 函數sayhi指向的記憶體位址
# 單個參數的函數
def sayhi(name):
print("hello",name)
print("my name is black girl....", name)
sayhi("tracy")
# 多個參數函數
def calc(x,y): # 定義算數函數
res = x**y
return res # 傳回函數執行結果
a,b = 5,8
c = calc(a,b) # 結果指派給變量c
print(c)
calc(2,10) # 直接寫入參數
1、形參
隻有在被調用時才配置設定記憶體單元,在調用結束時,即刻釋放所配置設定的記憶體單元。是以,形參隻在函數内部有效。函數調用結束傳回主調用函數後則不能再使用該形參變量
2、實參
可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們必須有确定的值,以便把這些值傳送給形參。是以應預先用指派,輸入等辦法使參數獲得确定值
def calc(x,y): # 形參
res = x**y
return res
a,b = 3,5
c = calc(a,b) # 實參
print(c)
d = calc(2,3) # 實參
3、預設參數
def stu_register(name,age,country,course):
print("注冊學生資訊".center(50,'-'))
print("姓名:",name)
print("age:" ,age)
print("國籍",country)
print("課程",course)
stu_register("山炮",22,"CN","python_devops")
stu_register("豐收",23,"CN","linux")
'''
由于很多人國籍都是中國,可以将country設定為預設參數
預設參數:
'''
def stu_register(name,age,course,country="CN"): # 非預設參數不能跟在預設參數後面
print("registration info".center(50,'-'))
print(name,age,country,course)
stu_register("jack",22,'c++') # 實參和形參按順序一一對應
stu_register("rain",32,'dance','Korean')
stu_register("Alfa",21,'python')
4、關鍵字參數
應用場景:正常情況下,給函數傳參數要按順序,不想按順序可以用關鍵參數
定義:指定了參數名的參數就叫關鍵參數
關鍵參數必須放在位置參數(以位置順序确定對應關系的參數)之後
def stu_register(name,age,course,country='CN'):
print("注冊學生資訊".center(50,'-'))
print("姓名:",name)
print("age:" ,age)
print("國籍",country)
print("課程",course)
stu_register("绮珊",course='Python',age=22,country='JP') # 後三個均為為關鍵參數置于name位置參數之後
# stu_register("杉樹",course='Python',22,country='JP') # 22為位置參數不能放在關鍵參數course之後
# stu_register("曼玉",22,age=25,country='JP') # age獲得多個賦
5、非固定參數(動态參數)
形式參數中出現*,傳遞的參數就可以不再是固定個數,會将傳過來的所有參數打包為元組。
def send_alert(msg,*users):
for u in users:
print('報警發送給',u)
# 方式一:
# 報警,十個運維人員
send_alert('注意系統資源别浪了','Alex','jack','tracy','wood')
# 方式二:
# send_alert('注意記憶體緊張',['alex','jack','tracy','wood']) # 傳入的參數是資料
send_alert('注意記憶體緊張',*['alex','jack','tracy','wood']) # 傳入的參數是數組内的元素
# 傳入的參數由(['alex','jack','tracy','wood']) ————>('alex','jack','tracy','wood')
如果動态參數後還有參數
# 方法一:
def send_redalert(msg,*users,age):
for u in users:
print('CPU緊張',u)
# send_redalert("alex","rain",22) # 22也會傳遞給*users
send_redalert("alex","rain",age=22)
# 方法二:
def func(name,*args,**kwargs):
print(name,args,kwargs)
func('Alex',22,'tesla','500w',addr='湖北',num=123332313)
# Alex (22, 'tesla', '500w') {'addr': '湖北', 'num': 123332313}
d = {'degree':'primary school'}
func('Peiqi',**d)
- *args代表位置參數,它會接收任意多個參數并把這些參數作為元組傳遞給函數。
- **kwargs代表的關鍵字參數,允許你使用沒有事先定義的參數名。
- 位置參數一定要放在關鍵字參數的前面。
優點:使用*args和**kwargs可以非常友善的定義函數,同時可以加強擴充性,以便日後的代碼維護。
三、函數的傳回值
傳回值:函數外部的代碼要想擷取函數的執行結果,可以在函數裡用return語句把結果傳回。
注意:
1、函數在執行過程中隻要遇到return語句,就會停止執行并傳回結果,可以了解return語句代表着函數的結束
2、如果未在函數中指定return,那這個函數的傳回值為None
def stu_register(name,age,course='PY',country='CN'):
print("注冊學生資訊".center(50,'-'))
print("姓名:", name)
print("age:", age)
print("國籍", country)
print("課程", course)
if age > 22:
return False
else:
return True
registration_status = stu_register('阿斯頓',22,course="全棧開發",country='JP')
if registration_status:
print("注冊成功".center(50,'-'))
else:
print("too old to be a student.")
'''
執行到return語句後,停止執行函數并傳回結果
'''
def stu_register(name,age,course):
print(name,age,course)
#
# if age > 22:
# return 'sdfsf' # 傳回值可以是任意值
# else:
# return True
#
# return None # 到return語句後,停止執行函數并傳回結果
# print('hahah')
# return 1
return [name,age]
status = stu_register('Peiqi',29,'安保')
print(status)
四、全局和局部變量
局部變量:函數内定義的變量,隻能在局部生效
全局變量:定義在函數外部一級代碼的變量,整個程式可用(由上到下可用)
在函數内部可以引用全局變量。
變量查找順序:如果全局和局部都有一個變量,函數查找變量的順序是由内而外的。兩個函數間互不可見
name = "Black girl" # 全局變量
def change_name():
# global name # (不建議使用global)在函數内修改全局變量,不能放在函數内局部變量後面
name = "黑色的姑娘" # 局部變量
print("在",name,"裡面...",id(name))
change_name()
print(name,id(name)) # 與函數内的變量内容完全不同
'''
輸出結果:
在 黑色的姑娘 裡面... 4302993904
Black girl 4316351984
'''
函數内可以修改字典、清單、集合、對象、類、元組内的清單
names = ['Alex','Black Girl','Peiqi']
def change_name():
names = ['Alex']
del names[2] # names整體的記憶體位址不能修改隻能引用,但其内部的元素是可以修改的
names[1] = "黑姑娘"
print(names)
change_name()
print(names)
'''
輸出結果:
['Alex', '黑姑娘']
['Alex', '黑姑娘']
'''
- 在函數中定義的變量稱為局部變量,在程式的一開始定義的變量稱為全局變量。
- 全局變量作用域是整個程式,局部變量作用域是定義該變量的函數。
- 當全局變量與局部變量同名時,在定義局部變量的函數内,局部變量起作用;在其它地方全局變量起作用。
五、作用域(scope)
作用域定義:一段程式代碼中所用到的名字并不總是有效/可用的,而限定這個名字的可用性的代碼範圍就是這個名字的作用域。
- python中一個函數就是一個作用域,局部變量放置在其作用域中
- C# Java中作用域{}
- 代碼定義完成後,作用域已經完成,作用域鍊向上查找
age = 18
def func1():
age = 73
def func2():
age = 84
print(age)
return 666
val = func1()
print(val)
'''
輸出:666
'''
# 函數名可以當作傳回值
age = 18
def func1():
age = 73
def func2():...
return func2 # 傳回一個函數名# val = func1()
print(val)
'''
輸出:<function func1.<locals>.func2 at 0x101462598>
'''
# 代碼寫完之後作用域已經生成,不管函數名傳到哪裡,隻要執行都回回定義的地方往上找
age = 18
def func1():
age = 73
def func2():
print(age)
return func2 # 傳回一個函數名不帶括号
val = func1()
val()
'''
輸出結果:73
'''
六、嵌套函數
嵌套函數,就是指在某些情況下,您可能需要将某函數作為另一函數的參數使用。
1、函數定義完成之後,沒有通過名字調用,内部代碼永遠不會執行
def func1():
print('alex')
def func2():
print('eric')
func1()
'''
輸出:alex
'''
def func1():
print('alex')
def func2():
print('eric')
func2()
func1()
'''
輸出:
alex
eric
'''
總結:
- 函數内部可以再次定義函數
- 執行函數需要被調用
2、嵌套函數尋找變量,優先自己函數,再找父級、爺爺級等,沒有就找全局變量(一層一層往上找)
age = 19
def func1():
age = 73
print(age) # 尋找變量,先找自己的函數内,沒有就找全局變量(一層一層往上找)
def func2():
age = 84
print(age) # 尋找變量,優先自己函數、再找父級、爺爺級,最後找全局變量
func2()
func1() # 輸出:73 84
# 測試二:
age1 = 19
def func1():
age1 = 73
def func2():
print(age1) # 按順序往上找,找到父級的age=73
func2()
func1() # 輸出:73
3、局部變量位置調整
age = 19
def func1():
def func2():
print(age)
age = 73
func2()
func1()
"""
輸出:
73
"""
age = 19
def func1():
def func2():
print(age)
func2()
age = 73
func1()
'''
執行報錯:free variable 'age' referenced before assignment in enclosing scope
73在func2後面,func2不知道該取哪個參數
'''
為了避免這種情況,聲明變量盡量寫在前面。
4、全局變量設定
age = 19
def func1():
global age # 此時已經拿到age=19,age=73還沒有執行
def func2():
print(age)
func2()
age = 73 # 此時修改全局age=73
func1()
print(age)
"""
輸出:
19
73
"""
age = 19
def func1():
global age
def func2():
print(age)
age = 73 # 将全局變量age改為73,再執行func2,函數沒有在func2\func1中找到age,繼續到全局找age,但全局已經修改為73
func2()
func1()
print(age)
"""
輸出:
73
73
"""
第一個程式,在global age時,函數已經拿到age=19,但此時age=73還沒有執行,此時執行func2函數,列印age=19。随後修改全局變量age=73,直接列印age,是以輸出73.
第二個程式,在global age時,函數拿到age=19,随後修改全局變量age=73,接着執行func2函數,列印age=73,列印此時的全局變量age,也同樣輸出73.