函式
Outline
·1.作用
·2.使用步驟
·3.引數
·4.回傳值
·5.說明檔案
·6.函式嵌套
·7.變數作用域
·8.多函式程式執行流程
·9.回傳值進階
·10.引數進階
·11.拆包和交換兩個變數的值
·12.參考
·13.可變與不可變型別
·14.遞回
·15.lambda運算式
·16.高階函式
1. 函式的作用
·函式是將 一段具有獨立功能的代碼塊整合到一個整體并命名,在需要的位置 呼叫這個名稱即可完成對應的需求
·函式在開發程序中,可以高效地實作 代碼重用
2. 函式的使用步驟
2.1 定義函式
·語法:
def 函式名(引數):
代碼1
代碼2
......
2.2 呼叫引數
·語法:
函式名(引數)
·注意:
1.對于不同的需求,引數可有可無
2.在Python中函式必須 先定義后使用
·實作功能時可以學習的地方:先搭建整體框架(復現需求),再補充需求內容
print('密碼正確登錄成功')
# 顯示"選擇功能"界面
print('查詢余額完畢')
# 顯示"選擇功能"界面
print('取了2000元錢')
# 顯示"選擇功能"界面
# 需求:復現ATM取錢功能
def select_fun():
# 功能:查詢余額、存款、取款
print("--------------------")
print("請選擇要辦理的業務")
print("查詢余額")
print("存款")
print("取款")
print("--------------------")
print("密碼正確!登錄成功!")
select_fun()
print("余額查詢完畢")
select_fun()
print("取了2000元")
密碼正確!登錄成功!
--------------------
請選擇要辦理的業務
查詢余額
存款
取款
--------------------
余額查詢完畢
--------------------
請選擇要辦理的業務
查詢余額
存款
取款
--------------------
取了2000元
3. 函式的引數
·思考:若定義了如下函式完成1+2地運算,如果想要這個函式變得更靈活,可以計算任何用戶指定的兩個數字的和,如何書寫程式?
# 定義函式
def add_num1():
result = 1 + 2
print(result)
# 呼叫函式
add_num1()
·分析:用戶要在呼叫函式的時候指定具體數字,那么在定義函式的時候就需要接收用戶指定的數字,函式呼叫時候指定的數字和定義函式時候接收的數字即是函式的引數,
# 實作任意兩數相加
def add_2num(a,b):
print(f"{a} + {b} = {a+b}")
add_2num(99,1)
99 + 1 = 100
3.1 引數傳遞
·在python中,型別是屬于物件的,而變數是沒有型別的:
a = [1,2,3]
a = 'lcj'
·在以上代碼中,[1,2,3]是一個list型別,'lcj’是一個string型別,而變數a是沒有型別的,他僅僅只是一個物件的參考(可以理解為一個指標),可以是指向list型別物件,也可以是指向string型別物件
3.1.1 可變型別物件及其引數傳遞
在python中,list、dict、set等是可以修改的物件,
·變數賦值 la=[1,2,3,4] 后再賦值 la[2]=5 則是將 list la 的第三個元素值更改,本身la沒有動,只是其內部的一部分值被修改了,
引數傳遞:
·類似 C++ 的參考傳遞,如 串列,字典,如 fun(la),則是將 la 真正的傳過去,修改后 fun 外部的 la 也會受影響
3.1.2 不可變型別物件及其引數傳遞
在python中,string、tuple、numbers是不可變資料型別
·變數賦值 a=5 后再賦值 a=10,這里實際是新生成一個 int 值物件 10,再讓 a 指向它,而 5 被丟棄,不是改變 a 的值,相當于新生成了 a,
引數傳遞:
·類似 C++ 的值傳遞,如整數、字串、元組,如 fun(a),傳遞的只是 a 的值,沒有影響 a 物件本身,如果在 fun(a) 內部修改 a 的值,則是新生成一個 a 的物件,
# 不可變型別物件引數傳遞
def change(a):
print(id(a)) # 指向的是同一個物件
a=10
print(id(a)) # 一個新物件
a=1
print(id(a))
change(a)
# 可變型別物件引數傳遞
# 可寫函式說明
def changeme( mylist ):
"修改傳入的串列"
mylist.append([1,2,3,4])
print ("函式內取值: ", mylist)
return
# 呼叫changeme函式
mylist = [10,20,30]
changeme( mylist )
print ("函式外取值: ", mylist)
140713493473056
140713493473056
140713493473344
函式內取值: [10, 20, 30, [1, 2, 3, 4]]
函式外取值: [10, 20, 30, [1, 2, 3, 4]]
4. 函式的回傳值
·在函式中,如果需要回傳結果給用戶,則需要使用函式回傳值,
# 計算任意兩數之和,并保存結果
def sum_num(a,b):
return a + b
result = sum_num(10,99)
print(result)
109
5. 函式的說明檔案
·語法:
def 函式名(引數):
""" 說明檔案的位置 """
代碼
......
·查看函式的說明檔案
help(函式名)
def test_fun():
"""
本函式用來測驗函式說明檔案作用
換行
"""
help(test_fun)
Help on function test_fun in module __main__:
test_fun()
本函式用來測驗函式說明檔案作用
換行
6.函式的嵌套呼叫
·函式的嵌套呼叫是指一個函式中又呼叫了另個函式
def testA():
print('---- testA start ----')
print("這是函式A執行的代碼塊")
print('---- testA done ----')
def testB():
print('---- testB start ----')
testA()
print('---- testB done ----')
testB()
---- testB start ----
---- testA start ----
這是函式A執行的代碼塊
---- testA done ----
---- testB done ----
7. 變數作用域
·變數作用域指的是變數生效的范圍,主要分為兩類:區域變數和全域變數
7.1 區域變數
·定義:區域變數是定義在函式體內部的變數,即只在函式體內部生效
·作用:在函式體內部,臨時保存資料,即當函式呼叫完成后,銷毀區域變數
# 區域變數
def test1():
A = 100
print(A)
test1()
print(A) # 會報錯
100
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-12-3bd390f0e5e9> in <module>
5
6 test1()
----> 7 print(A) # 會報錯
NameError: name 'A' is not defined
7.2 全域變數
·全域變數是指在函式體內、外都可以生效的變數
# 定義全域變數
B = 100
def test2():
print(B) # 訪問全域變數B,并列印其存盤的資料
def test3():
print(B) # 訪問全域變數B,并列印其存盤的資料
test2()
test3()
100
100
·思考:如果test3需要修改變數B為200,應該如何修改?
# 修改全域變數--1
B = 100
listx = [10,20,30]
def test2():
print(B) # 訪問全域變數B,并列印其存盤的資料
def test3():
B = 200
listx.append([1,2,3])
print(B) # 訪問全域變數B,并列印其存盤的資料
test2()
test3()
print(f"全域變數B的值:{B}")
print(listx)
100
200
全域變數B的值:100
[10, 20, 30, [1, 2, 3]]
我們發現這樣修改全域變數其實并沒有生效,最后列印出來的全域變數B的值仍然為100;
這里我們添加一個串列作為對照,可以很清楚的看到,串列在函式中的修改中是生效了的,這就是我們上文提到的可變與不可變資料型別的區別,作為指向不可變資料物件的B變數,在test3中試圖修改時,其實是函式在內部創建了一個名字也叫B的區域變數;而作為可變資料型別的串列,則是將串列物件直接傳入test3函式中修改,
最后,我們如何在函式體內修改全域變數呢?
→使用global關鍵字
# 修改全域變數--2
B = 100
def test2():
print(B) # 訪問全域變數B,并列印其存盤的資料
def test3():
# 使用global關鍵字宣告B是全域變數
global B
B = 200
print(B) # 訪問全域變數B,并列印其存盤的資料
test2()
test3()
print(f"全域變數B的值:{B}")
100
200
全域變數B的值:200
8. 多函式程式執行流程
·在實際開發程序中,一個程式往往由多個函陣列成,并且多個函式可能會共享某些資料
8.1 共用全域變數
# 定義全域變數
glo_num = 100
def test1():
global glo_num
glo_num = 1 # 修改全域變數
def test2():
print(glo_num) # 呼叫全域變數
test2() # 列印修改前的全域變數
test1() # 修改全域變數
test2() # 列印修改后的全域變數
100
1
8.2 回傳值作為引數傳遞
def test1():
return 99
def test2(num):
print(num)
result = test1() # 保存test1的回傳值
test2(result) # 將回傳值作為引數傳遞到test2中
99
9. 回傳值進階
·思考:如果一個函式有多個return陳述句,執行結果會怎樣?
Answer:只會執行第一個,因為return會退出當前函式,導致第一個return后面的代碼不會再執行
·如何回傳多個值?
# 多個回傳值函式
def return_2():
return 1,2,3
result = return_2()
print(result)
print(type(result))
(1, 2, 3)
<class 'tuple'>
注意:
·return a,b寫法在回傳多個資料的時候,默認為元組型別
·return后面可以連接串列、元組或字典,以回傳多個值
10. 引數進階
10.1 位置引數
·定義:呼叫函式時根據函式定義的引數位置來傳參
·注意:傳遞和定義引數的順序及個數必須一致!
# 位置引數
def fun_location(name,age,gender):
print(f"Your name : {name}\nYour age : {age}\nYour gender : {gender}")
fun_location('lee',20,'male')
Your name : lee
Your age : 20
Your gender : male
10.2 關鍵字引數
·通過“key=value”形式加以指定,使用關鍵字引數允許函式呼叫時引數的順序與宣告時不一致,因為 Python 解釋器能夠用引數名匹配引數值,
·注意:函式呼叫時,如果有位置引數時,位置引數必須在關鍵字引數的前面,但關鍵字引數之間不存在先后順序,
# 關鍵字引數
def fun_keyword(name,age,gender):
print(f"Your name : {name}\nYour age : {age}\nYour gender : {gender}")
fun_keyword('Lee',age=20,gender='male')
fun_keyword(age=21,gender='male',name='jcl')
Your name : Lee
Your age : 20
Your gender : male
Your name : jcl
Your age : 21
Your gender : male
10.3 默認引數
·也叫預設引數,用于定義函式,為引數提供默認值,呼叫函式時可不傳該默認引數的值
·注意:
1.所有位置引數必須出現在默認引數之前,包括函式定義和呼叫
2.函式呼叫時,如果為默認引數傳值則修改默認引數值,否則使用默認值
# 默認引數
def fun_tolerant(name,age,gender='男'):
print(f"Your name : {name}\nYour age : {age}\nYour gender : {gender}")
fun_tolerant('TOM',21)
fun_tolerant('Rose',19,'female')
Your name : TOM
Your age : 21
Your gender : 男
Your name : Rose
Your age : 19
Your gender : female
10.4 不定長引數
·也叫可變引數,用于不確定呼叫的時候會傳遞多少個引數(也可以不傳參)的場景,此時可用包裹(packing)位置引數,或者包裹關鍵字引數,來進行引數傳遞,
·加了星號 * 的引數會以元組(tuple)的形式匯入,存放所有未命名的變數引數,
# 包裹位置傳遞
def user_info(*args):
print(args)
user_info('Tom')
user_info('Tom',18,'male')
('Tom',)
('Tom', 18, 'male')
·注意:傳進的所有引數都會被args變數收集,它會根據傳進引數的位置合并為一個元組(tuple),args是元組型別,這就是包裹位置傳遞,
# 包裹關鍵字傳遞
def user_info(**kvargs):
print(kvargs)
user_info(name='lee',age=18,gender='male')
{'name': 'lee', 'age': 18, 'gender': 'male'}
11. 拆包和交換變數值
11.1 拆包
# 拆包:元組
def return_num():
return 1,99
num1,num2 = return_num()
print("元組拆包")
print(num1)
print(num2)
print('-'*10)
# 拆包:字典
dict1 = {'name':'lee','age':20}
a,b = dict1
print("字典拆包") # 字典拆包,取出來的是字典的key值
print(a)
print(b)
print(dict1[a])
print(dict1[b])
元組拆包
1
99
----------
字典拆包
name
age
lee
20
11.2 交換變數值
·需求:變數a = 10,b = 20,交換兩個變數的值
# 常規方法:借助中間變數實作交換
a,b = 10,20
c = 0 # 定義中間變數
c = a # 將a的值儲存到c
a = b # 將b的值賦給a
b = c # 將a的值賦給b
print(f"a的值:{a}\nb的值:{b}")
a的值:20
b的值:10
# 方便方法!
a, b = 1, 2
print(f"交換前:\na的值:{a}\nb的值:{b}")
a, b = b, a
print(f"交換后:\na的值:{a}\nb的值:{b}")
交換前:
a的值:1
b的值:2
交換后:
a的值:2
b的值:1
12. 參考
12.1 了解參考
·python中,值是靠參考來傳遞的
我們可以用id()來判斷兩個變數是否為同一個值的參考
id可以理解為那塊記憶體的地址標識
# 1. 不可變資料型別:以int為例
a = 1
b = a
print(b)
print(f"a的地址:{id(a)}\nb的地址:{id(b)}")
a = 2
print(b) # 說明int為不可變資料型別
print(f"a的地址:{id(a)}\nb的地址:{id(b)}")
1
a的地址:140713493473056
b的地址:140713493473056
1
a的地址:140713493473088
b的地址:140713493473056
# 2. 可變資料型別:以list為例
aa = [10,20]
bb = aa
print(bb)
print(f"aa的地址:{id(aa)}\nbb的地址:{id(bb)}")
aa.append(99)
print(bb) # bb的值也變化,說明串列為可變資料型別
print(f"aa的地址:{id(aa)}\nbb的地址:{id(bb)}")
[10, 20]
aa的地址:1658821373440
bb的地址:1658821373440
[10, 20, 99]
aa的地址:1658821373440
bb的地址:1658821373440
12.2 參考當作實參
def test1(a):
print(f"a值為:{a}\na地址為:{id(a)}")
a += a
print(f"a值為:{a}\na的地址:{id(a)}")
# int
b = 100
test1(b)
# list
c = [11,22]
test1(c)
a值為:100
a地址為:140713493476224
a值為:200
a的地址:140713493479424
a值為:[11, 22]
a地址為:1658825582336
a值為:[11, 22, 11, 22]
a的地址:1658825582336
13. 可變與不可變資料型別
·可變資料型別:串列、字典、集合
·不可變資料型別:Numbers、字串、元組
14. 遞回
14.1 應用場景
·遞回是一種編程思想:
1.在我們日常開發中,如果要遍歷一個檔案夾下面所有的檔案,通常會使用遞回來實作;
2.在后續的演算法課程中,很多演算法都離不開遞回,例如:快速排序,
·特點:
1.函式內部自己呼叫自己
2.必須有出口
# 遞回應用:累加
def sum_num(num):
# 判斷:如果為1則直接回傳1-----遞回的出口
if num == 1:
return 1
# 如果不是1,則遞回求解
return num + sum_num(num-1)
result = sum_num(10) # 1-10累加
print(result)
55
15. lambda運算式
·也叫匿名函式:
所謂匿名,意即不再使用 def 陳述句這樣標準的形式定義一個函式,
lambda 只是一個運算式,函式體比 def 簡單很多,
lambda的主體是一個運算式,而不是一個代碼塊,僅僅能在lambda運算式中封裝有限的邏輯進去,
lambda 函式擁有自己的命名空間,且不能訪問自己引數串列之外或全域命名空間里的引數,
雖然lambda函式看起來只能寫一行,卻不等同于C或C++的行內函式,后者的目的是呼叫小函式時不占用堆疊記憶體從而增加運行效率,
·應用場景:如果一個函式有一個回傳值,且只有一句代碼,則可以使用lambda運算式簡化,
·語法:
lambda 引數串列 : 運算式
·注意事項:
1.lambda運算式的引數可有可無,函式的引數在lambda運算式中完全適用,
2.lambda運算式能接收任何數量的引數但只能回傳一個運算式的值,
3.直接列印lambda運算式,輸出的是此lambda的記憶體地址
# lambda運算式計算a+b
fn = lambda a, b: a + b
print(fn)
print(fn(1,2))
<function <lambda> at 0x00000182399A00D0>
3
# lambda的引數形式
# 無參
fn1 = lambda:100
print(fn1())
# 一個引數
fn2 = lambda a: a
print(fn2("Hello,World!"))
# 默認引數
fn3 = lambda a, b, c=100: a + b + c
print(fn3(5,3))
# 可變引數:*args
fn4 = lambda *args: args
print(fn4(1,2,3))
# 可變引數:**kvargs
fn5 = lambda **kvargs: kvargs
print(fn5(name='lee',age=20))
100
Hello,World!
108
(1, 2, 3)
{'name': 'lee', 'age': 20}
·注意:可變引數*args傳入lambda后回傳值為元組
# lambda運算式應用1---帶判斷的lambda
fn1 = lambda a, b: a if a > b else b
print(fn1(40,99))
99
# 資料按字典key的值排序
students = [
{'name': 'TOM', 'age': 20},
{'name': 'ROSE', 'age': 19},
{'name': 'Jack', 'age': 22}
]
# 按name升序排列
students.sort(key=lambda x: x['name'])
print(students)
# 按name降序排列
students.sort(key=lambda x: x['name'],reverse=True)
print(students)
# 按age值升值排序
students.sort(key=lambda x: x['age'])
print(students)
[{'name': 'Jack', 'age': 22}, {'name': 'ROSE', 'age': 19}, {'name': 'TOM', 'age': 20}]
[{'name': 'TOM', 'age': 20}, {'name': 'ROSE', 'age': 19}, {'name': 'Jack', 'age': 22}]
[{'name': 'ROSE', 'age': 19}, {'name': 'TOM', 'age': 20}, {'name': 'Jack', 'age': 22}]
16. 高階函式
·把函式作為引數傳入,這樣的函式稱為高階函式,高階函式是函式式編程的體現,函式式編程就是指這種高度抽象的編程范式,
"""
abs():求數字的絕對值
round():對數字四舍五入
需求:任意兩個數字,按照指定要求整理數字后求和
"""
# 方法1.
def add_num(a,b):
return abs(a)+abs(b)
result = add_num(-1,9)
print(result)
# 方法2.
def sum_num(a,b,f):
return f(a)+f(b)
result2 = sum_num(-1,9,abs)
print(result2)
result3 = sum_num(1.2,9.4,round)
print(result3)
10
10
10
16.1 內置高階函式
16.1.1 map()
·map(func, lst),將傳入的函式變數func作用到lst變數的每個元素中,并將結果組成新的迭代器(Python3)回傳,
# 需求:計算list序列中各個數字的2次方
list1 = [1,2,3,4,5]
func = lambda x: x**2
result = map(func,list1)
print(result)
print(list(result))
<map object at 0x000001823A18C280>
[1, 4, 9, 16, 25]
16.1.2 reduce()
·reduce(func,lst),其中func必須有兩個引數,每次func計算的結果繼續和序列的下一個元素做累積計算,
·注意:reduce()傳入的引數func必須接收兩個引數
# 需求:計算list1序列中各個數字的累加和
import functools
list1 = [1,2,3,4,5]
func = lambda a, b: a + b
result = functools.reduce(func,list1)
print(result)
15
16.1.3 filter()
·filter(func, lst)函式用于過濾序列, 過濾掉不符合條件的元素, 回傳一個 filter 物件,如果要轉換為串列, 可以使用 list() 來轉換,
# filter()
list1 = [1,2,3,4,5,6,7,8,9,10]
func = lambda x: x % 2 == 0
result = filter(func,list1)
print(result)
print(list(result))
<filter object at 0x00000182395B3340>
[2, 4, 6, 8, 10]
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/277034.html
標籤:python
下一篇:Python控制臺輸出俄羅斯方塊
