問:為什么總是把簡書筆記寫的那么長這樣沒人看的
其實我在簡書上記筆記只是方便我日后想不起來的時候Ctrl+f,把很多知識點寫在一起雖然閱讀體驗不好,可是Ctrl+f起來超級方便,能夠避免開很多窗口~
1.函數(shù)的定義和調(diào)用
函數(shù):實現(xiàn)某個功能的代碼塊(其實就是一段代碼)
學(xué)習(xí)函數(shù)目的:提高代碼的復(fù)用性,減少代碼的冗余
# 定義函數(shù)
def show():
# 實現(xiàn)某個功能的代碼要放到函數(shù)里面
for _ in range(3):
print("人生苦短")
# 調(diào)用函數(shù)
show()
############## 輸出結(jié)果 ###############
人生苦短
人生苦短
人生苦短
提示:定義函數(shù)的時候,函數(shù)里面的代碼不會執(zhí)行,當調(diào)用函數(shù)的時候函數(shù)里面的代碼才會執(zhí)行。
調(diào)用函數(shù)的格式: 函數(shù)名()
2. 函數(shù)的文檔說明
函數(shù)的文檔說明: 解釋說明函數(shù)的功能的。
def show():
"""實現(xiàn)兩個數(shù)字和計算"""
result = 1 + 2
print(result)
show()
############## 輸出結(jié)果 ###############
3
查看函數(shù)的文檔說明,使用help()函數(shù)。
執(zhí)行help(show)代碼可以看到show函數(shù)的文檔說明:
help(show)
############## 輸出結(jié)果 ###############
Help on function show in module __main__:
show()
實現(xiàn)兩個數(shù)字和計算
2.帶有參數(shù)的函數(shù)
函數(shù)帶有參數(shù)的語法格式 :
def 函數(shù)名(形參1, 形參2, .....):
實現(xiàn)某個功能的具體代碼
函數(shù)名(實參1, 實參2, ....)
定義帶有參數(shù)的函數(shù):
# 定義帶有參數(shù)的函數(shù)
def sum_num(num1, num2):
result = num1 + num2
print(result)
#調(diào)用函數(shù),并給函數(shù)傳遞參數(shù)
sum_num(5, 3)
############## 輸出結(jié)果 ###############
8
函數(shù)調(diào)用流程:
- 調(diào)用函數(shù)先回到函數(shù)的定義,給函數(shù)的參數(shù)傳參;
- 給函數(shù)參數(shù)傳參完成以后,執(zhí)行函數(shù)里面的代碼;
- 當函數(shù)里面的代碼執(zhí)行完成以后,會回到函數(shù)之前調(diào)用的地方,然后代碼可以再繼續(xù)往下執(zhí)行。
需求:從屏幕接受三個數(shù)字,計算第一個數(shù)加第二個數(shù)減去第三個數(shù)字的結(jié)果。
def sum_num(num1, num2, num3):
result = num1 + num2 - num3
print(result)
num1 = int(input("請輸入第一個數(shù)字:"))
num2 = int(input("請輸入第二個數(shù)字:"))
num3 = int(input("請輸入第三個數(shù)字:"))
sum_num(num1, num2, num3)
3. 函數(shù)的返回值
函數(shù)的返回值:當調(diào)用函數(shù)的時候,函數(shù)內(nèi)部的數(shù)據(jù)想要讓函數(shù)外界使用,需要通過
return關(guān)鍵字把函數(shù)內(nèi)部的數(shù)據(jù)進行返回。
所謂“返回值”,就是程序中函數(shù)完成一件事情后,最后給調(diào)用者的結(jié)果
# 定義一個函數(shù),實現(xiàn)兩個數(shù)字和的計算,并把計算后的結(jié)果返回出去
def sum_num(num1, num2):
result = num1 + num2
# 把函數(shù)內(nèi)部的數(shù)據(jù)通過return返回給函數(shù)的調(diào)用者
return result
# 調(diào)用函數(shù)
value = sum_num(1, 2)
# 打印出函數(shù)的返回值
print(value)
函數(shù)返回值的擴展
擴展1:return可以結(jié)合None使用
定義一個函數(shù),該函數(shù)可以查找任意一個參數(shù)是否在字符串hello中,如果在返回該字母,如果不在則返回None:
def search_str(params):
my_str = "hello"
for value in my_str:
if value == params:
return value
else:
return None
我們給search_str()函數(shù)傳遞參數(shù)做個測試:
result = search_str("x")
print(result)
############## 輸出結(jié)果 ###############
None
擴展2:多層循環(huán)結(jié)合
return關(guān)鍵字使用,可以讓多層循環(huán)終止循環(huán)。
首先,定義一個for循環(huán)遍歷列表的函數(shù)
# 定義函數(shù)
def show():
my_list = ["Life", "is", "short", "you", "need", "Python"]
for value in my_list:
print(value, end=" ")
# 調(diào)用函數(shù)
show()
############## 輸出結(jié)果 ###############
Life is short you need Python
結(jié)合return關(guān)鍵字,改變函數(shù):當遍歷到short時,終止循環(huán):
def show():
my_list = ["Life", "is", "short", "you", "need", "Python"]
for value in my_list:
print(value, end=" ")
if value == "short":
return
show()
############## 輸出結(jié)果 ###############
Life is short
擴展3: 函數(shù)沒有提供返回值,那么調(diào)用函數(shù)的時候如果使用變量接收返回結(jié)果,那么返回的結(jié)果是None。
# 定義一個函數(shù)
def show():
my_name = "huangjing"
print("my name's", my_name)
# 調(diào)用函數(shù)
result = show()
print("result is", result)
############## 輸出結(jié)果 ###############
my name's huangjing
result is None
總結(jié):
- 當函數(shù)執(zhí)行了return表示函數(shù)執(zhí)行結(jié)束,即使后面有更多的代碼,也不會執(zhí)行。
- return關(guān)鍵字只能在函數(shù)或者方法內(nèi)部使用。
4. 函數(shù)的嵌套調(diào)用
函數(shù)的嵌套調(diào)用:在函數(shù)里面又調(diào)用其他函數(shù),這種格式就是函數(shù)的嵌套調(diào)用。
寫一個嵌套函數(shù)task(),其中task()中嵌套有task1()和task2():
def task1():
print("好好學(xué)習(xí)")
def task2():
print("天天向上")
def task():
print("悄悄咪咪的告訴你:")
task1()
task2()
task()
############## 輸出結(jié)果 ###############
悄悄咪咪的告訴你:
好好學(xué)習(xí)
天天向上
嵌套函數(shù)的應(yīng)用
需求:定義一個可以打印一條橫線的函數(shù),然后再利用該函數(shù)寫一個嵌套函數(shù)使嵌套函數(shù)可以打印自定義行數(shù)的橫線。
可以打印一條橫線的函數(shù):
# 定義一個可以打印一條橫線的函數(shù)
def print_one_line():
print("-" * 20)
# 調(diào)用函數(shù)
print_one_line()
############## 輸出結(jié)果 ###############
--------------------
打印自定義行數(shù)的橫線:
def print_custom_line(rows):
for value in range(rows):
print_one_line()
看下整體效果:
def print_one_line():
print("-" * 20)
def print_custom_line(rows):
for value in range(rows):
print_one_line()
print_custom_line(4)
############## 輸出結(jié)果 ###############
--------------------
--------------------
--------------------
--------------------
5. 局部變量和全局變量
局部變量
局部變量:在函數(shù)內(nèi)定義的變量稱為局部變量。
def show():
# 定義了一個局部變量
num1 = 100
# 局部變量的作用域:只能在函數(shù)內(nèi)部使用,無法在函數(shù)外使用
print("函數(shù)內(nèi)的變量:", num1)
# 調(diào)用函數(shù)
show()
測試:在函數(shù)外部使用局部變量
print(num1)
######## 報錯信息為:########
NameError: name 'num1' is not defined
總結(jié):
- 局部變量的作用:臨時存儲函數(shù)內(nèi)的數(shù)據(jù),當函數(shù)執(zhí)行結(jié)束時,局部變量保存的數(shù)據(jù)會銷毀,在內(nèi)存中進行釋放。
- 局部變量的作用域:只能在函數(shù)內(nèi)部使用,無法在函數(shù)外使用。
全局變量
全局變量:在函數(shù)外定義的變量稱為全局變量。
# 定義全局變量
g_num = 1000
def show():
# 全局變量可以在不同函數(shù)內(nèi)使用
print("show函數(shù)使用的全局變量:", g_num)
def show_info():
# 全局變量可以在不同函數(shù)內(nèi)使用
print("show_info函數(shù)使用的全局變量:", g_num)
show()
show_info()
# 測試:全局變量還可以在函數(shù)外部使用
print("函數(shù)外使用的全局變量為:", g_num)
############## 輸出結(jié)果 ###############
show函數(shù)使用的全局變量: 1000
show_info函數(shù)使用的全局變量: 1000
函數(shù)外使用的全局變量為: 1000
總結(jié):
- 全局變量的作用域(使用范圍): 可以在不同函數(shù)內(nèi)或者函數(shù)外使用這個全局變量。
- 全局變量的作用:可以在不同函數(shù)內(nèi)共享數(shù)據(jù)(全局變量數(shù)據(jù))
6.修改全局變量
在函數(shù)內(nèi)修改全局變量需要使用關(guān)鍵字
global。
我們先看一下,在函數(shù)內(nèi)如果不使用關(guān)鍵字 global來修改全局變量會出現(xiàn)什么情況:
# 定義全局變量
g_num = 100
def modify_value():
#其實這里沒有對全局變量進行修改,而是定義了一個局部變量,只不過局部變量的名字和全局變量的名字相同而已
g_num = 200
print(g_num)
modify_value()
print(g_num)
############## 輸出結(jié)果 ###############
200
100
我們發(fā)現(xiàn)全局變量并沒有發(fā)生改變。還是之前的100。
使用關(guān)鍵字 global來修改全局變量:
g_num = 100
def modify_value():
global g_num
g_num = 200
print(g_num)
modify_value()
print(g_num)
############## 輸出結(jié)果 ###############
200
200
7. 多個函數(shù)共享數(shù)據(jù)
多個函數(shù)共享數(shù)據(jù)的操作:
- 全局變量:全局變量可以在不同函數(shù)內(nèi)共享數(shù)據(jù)(全局變量)
- 返回值(return 數(shù)據(jù)):通過返回值也可以在不同函數(shù)內(nèi)共享數(shù)據(jù)(返回的數(shù)據(jù))
全局變量共享數(shù)據(jù)的操作:
g_num = 1
def modify_value():
# 修改全局變量的數(shù)據(jù)
global g_num
g_num = 2
def show():
print("show:", g_num)
modify_value()
show()
############## 輸出結(jié)果 ###############
show: 2
以上可以看出,全局變量可以在modify_value()函數(shù)和show()函數(shù)中同時使用。
返回值共享數(shù)據(jù)的操作:
def return_value():
msg = "嘻嘻"
# 通過return把數(shù)據(jù)返回給函數(shù)的調(diào)用者,可以完成數(shù)據(jù)的共享操作
return msg
def show_info():
# 調(diào)用帶有返回值得函數(shù)
value = return_value()
print("show_info:", value)
def show_msg():
msg = return_value()
print("show_msg:", msg)
show_info()
show_msg()
############## 輸出結(jié)果 ###############
show_info: 嘻嘻
show_msg: 嘻嘻
8. return返回多個值
return返回多個數(shù)據(jù)的解決方案:把多個數(shù)據(jù)封裝到一個容器類型里面,這樣通過return可以一次性返回多個數(shù)據(jù)。
返回列表:(返回元組同理)
# 定義函數(shù)
def return_more_value():
#一次性返回多個數(shù)據(jù)
return [1, 3, 5]
# 調(diào)用函數(shù)
result = return_more_value()
print(result, type(result))
############## 輸出結(jié)果 ###############
[1, 3, 5] <class 'list'>
返回字典:
# 定義函數(shù)
def return_more_value():
#一次性返回多個數(shù)據(jù)
return {"name": "林黛玉", "age": 20}
# 調(diào)用函數(shù)
result = return_more_value()
print(result, type(result))
############## 輸出結(jié)果 ###############
{'name': '林黛玉', 'age': 20} <class 'dict'>
9. 函數(shù)的缺省參數(shù):
缺省參數(shù):形參設(shè)置了默認值,那么這個形參就是缺省參數(shù)。
缺省參數(shù)的特點:
- 當調(diào)用函數(shù)時如果給缺省參數(shù)傳值了,那么使用傳入的數(shù)據(jù);
- 當調(diào)用函數(shù)時如果沒有給缺省參數(shù)傳值,那么使用缺省的參數(shù)默認值。
缺省參數(shù)的注意點:
- 缺省參數(shù)后面不能再定義普通參數(shù);
- 缺省參數(shù)后面還可以再次定義缺省參數(shù)
不給缺省參數(shù)傳值,缺省參數(shù)使用默認值:
# 此時的age參數(shù)就是缺省參數(shù)
def show(name, age=18, sex="男"):
print("姓名:", name, "年齡:", age, "性別:", sex)
# 不給缺省參數(shù)傳值,缺省參數(shù)使用默認值
show("賈寶玉")
############## 輸出結(jié)果 ###############
姓名: 賈寶玉 年齡: 18 性別: 男
給缺省參數(shù)傳值了,那么使用傳入的數(shù)據(jù):
def show(name, age=18, sex="男"): # 此時的age參數(shù)就是缺省參數(shù)
print("姓名:", name, "年齡:", age, "性別:", sex)
show("林黛玉", 20, "女")
############## 輸出結(jié)果 ###############
姓名: 林黛玉 年齡: 20 性別: 女
10. 調(diào)用函數(shù)傳參的三種方式
- 按照位置參數(shù)的方式進行傳參, 注意點:強調(diào)的是調(diào)用函數(shù)時位置參數(shù)的順序要和函數(shù)定義時參數(shù)的順序保持一致;
- 按照關(guān)鍵字參數(shù)的方式進行傳參, 注意點:強調(diào)的是調(diào)用函數(shù)是關(guān)鍵字的名字要和函數(shù)定義時參數(shù)的名字保持一致;
- 前面是按照位置參數(shù)的方式進行傳參后面是關(guān)鍵字參數(shù)的方式進行傳參。
首先我們先定義一個函數(shù):
def show_info(name, age):
print("姓名:", name, "年齡:", age)
接下來沒我,我們按照不同的方式進行傳參
按照位置參數(shù)的方式進行傳參:
positional argument: 表示位置參數(shù)
show_info("李四", 30)
按照關(guān)鍵字參數(shù)的方式進行傳參:
keyword argument: 表示關(guān)鍵字參數(shù)
show_info(name="李四", age=30)
前面是按照位置參數(shù)的方式進行傳參后面是關(guān)鍵字參數(shù)的方式進行傳參:
show_info("李四", age=30)
注意:如果前面使用關(guān)鍵字參數(shù)后面必須使用關(guān)鍵字參數(shù)
11. 函數(shù)的不定長參數(shù)
函數(shù)的不定長參數(shù):函數(shù)參數(shù)的個數(shù)不確定,可能是0個或者1個或者多個這樣的參數(shù)稱為不定長參數(shù)。
不定長參數(shù)可以分為兩種:
- 不定長位置參數(shù): *args,提示:當調(diào)用函數(shù)時,所有的位置參數(shù)封裝成一個元組給args參數(shù);
- 不定長關(guān)鍵字參數(shù): **kwargs,提示:當調(diào)用函數(shù)時,所有的關(guān)鍵字參數(shù)封裝成字典給kwargs參數(shù)
缺省參數(shù)結(jié)合不定長位置參數(shù)使用
注意點:把缺省參數(shù)放到不定長位置參數(shù)的后面。
如果不這樣操作,那按照位置參數(shù)的方式進行傳參時,這里的缺省參數(shù)的默認值永遠使用不了。聽上去很復(fù)雜的樣子,其實稍微操作一下非常容易理解
def show(name, age=18, *args):
print("name:", name, "age:", age, "args:", args)
# 調(diào)用函數(shù)時使用位置參數(shù)的方式進行傳參
show("李四", 20, 1, 2, 3)
############## 輸出結(jié)果 ###############
name: 李四 age: 20 args: (1, 2, 3)
我們可以看到在按照位置參數(shù)的方式進行傳參時,第二個參數(shù)默認給了age參數(shù),剩下的所有數(shù)據(jù)打包成元組的形式傳給了不定長位置參數(shù)args,這里的缺省參數(shù)的默認值永遠使用不了。
解決辦法:把缺省參數(shù)放到不定長位置參數(shù)的后面。
def show(name, *args, age=18):
print("name:", name, "age:", age, "args:", args)
show("李四", 20, 1, 2, 3)
############## 輸出結(jié)果 ###############
name: 李四 age: 18 args: (20, 1, 2, 3)
也可以在傳參的時候,修改默認參數(shù)
def show(name, *args, age=18):
print("name:", name, "age:", age, "args:", args)
show("李四", 20, 1, 2, age=30)
############## 輸出結(jié)果 ###############
name: 李四 age: 30 args: (20, 1, 2)
缺省參數(shù)結(jié)合不定長位置參數(shù)和不定長關(guān)鍵字參數(shù)的使用
注意點:不定長關(guān)鍵字參數(shù)需要放到所有參數(shù)的最后面
def show(name, *args, age=18, **kwargs):
print("name:", name, "age:", age, "args:", args, "kwargs:", kwargs)
show("張三", 1, 3, 5)
show("王五", 1, 3, 5, 20, a=1, b=2, c=3, age=40)
############## 輸出結(jié)果 ###############
name: 張三 age: 18 args: (1, 3, 5) kwargs: {}
name: 王五 age: 40 args: (1, 3, 5, 20) kwargs: {'a': 1, 'b': 2, 'c': 3}
“王五”的例子說明了:當使用關(guān)鍵字傳參的時候,優(yōu)先判斷有沒有對于的參數(shù)名,如果有數(shù)據(jù)給對于的參數(shù)名,否則kwargs參數(shù)。
不定長參數(shù)的擴展
在函數(shù)定義的時候,可以使用不定長位置參數(shù)*args和不定長關(guān)鍵字參數(shù)**kwargs來定義。在調(diào)用的時候也可以用同樣的方法來拆包
比如,我們把要傳的位置參數(shù)都封裝到了元組里面,把關(guān)鍵字參數(shù)都封裝到了字典里面
my_tuple = (1, 2)
my_dict = {"a": 1, "b": 2}
使用show(*my_tuple)調(diào)用所有不定長位置參數(shù):
# *my_tuple: 表示對元組進行拆包,把元組中的每項數(shù)據(jù)按照位置參數(shù)的方式進行傳參
show(*my_tuple) # 等價于 show(1, 2)
使用show(**my_dict)調(diào)用所有不定長關(guān)鍵字參數(shù):
show(**my_dict) # 等價于 show(a=1, b=2)
show(*my_tuple, **my_dict) # 等價于show(1, 2, a=1, b=2)
注意點:
*my_tuple和**my_dict不能單獨使用, 只能結(jié)合不定長位置參數(shù)和不定長關(guān)鍵字參數(shù)使用。
看實戰(zhàn)效果
show(*my_tuple) 這里等價于show(a=1, b=2)
def show(*args, **kwargs):
print(args, kwargs)
my_tuple = (1, 2)
my_dict = {"a": 1, "b": 2}
show(*my_tuple)
############## 輸出結(jié)果 ###############
(1, 2) {}
show(**my_dict) 等價于 show(a=1, b=2)
def show(*args, **kwargs):
print(args, kwargs)
my_tuple = (1, 2)
my_dict = {"a": 1, "b": 2}
show(**my_dict)
############## 輸出結(jié)果 ###############
() {'a': 1, 'b': 2}
show(*my_tuple, **my_dict) 等價于show(1, 2, a=1, b=2)
def show(*args, **kwargs):
print(args, kwargs)
my_tuple = (1, 2)
my_dict = {"a": 1, "b": 2}
show(*my_tuple, **my_dict)
############## 輸出結(jié)果 ###############
(1, 2) {'a': 1, 'b': 2}
12. 拆包
拆包:使用不同變量保存容器類型中的每一個數(shù)據(jù),這樣的操作就是拆包。
注意點:拆包是結(jié)合容器類型使用的, 變量的個數(shù)要和容器類型中數(shù)據(jù)個數(shù)要一致
容器類型: 字符串,列表,元組,字典,range,集合(set)
對字符串進行拆包:
my_str = "abc"
value1, value2, value3 = my_str
print(value1, value2, value3)
############## 輸出結(jié)果 ###############
a b c
對列表進行拆包:
my_list = [1, 2, 3]
value1, value2, value3 = my_list
print(value1, value2, value3)
############## 輸出結(jié)果 ###############
1 2 3
對元組進行拆包:
my_tuple = (2, 2, 3)
value1, value2, value3 = my_tuple
print(value1, value2, value3)
############## 輸出結(jié)果 ###############
2 2 3
對字典進行拆包:
my_dict = {"name": "李四", "age": 20}
value1, value2 = my_dict
print(value1, value2)
############## 輸出結(jié)果 ###############
name age
對字典直接進行拆包,獲取的是每一個key,對values進行拆包:
my_dict = {"name": "李四", "age": 20}
value1, value2 = my_dict.values()
print(value1, value2)
############## 輸出結(jié)果 ###############
李四 20
對range進行拆包:
my_range = range(1, 3)
value1, value2 = my_range
print(value1, value2)
############## 輸出結(jié)果 ###############
1 2
拆包應(yīng)用場景
拆包應(yīng)用場景一:用拆包來獲取容器類型中的每一個數(shù)據(jù)
def return_value():
return 1, 3, 5
result = return_value()
print(result, type(result))
############## 輸出結(jié)果 ###############
(1, 3, 5) <class 'tuple'>
上面定義的return_value()函數(shù)返回了一個元組,接下來我們可以用拆包來獲取元組中的每一個數(shù)據(jù):
def return_value():
return 1, 3, 5
# 拆包: 獲取容器類型中的每一個數(shù)據(jù)
value1, value2, value3 = return_value()
print(value1, value2, value3)
############## 輸出結(jié)果 ###############
1 3 5
拆包應(yīng)用場景二:用拆包交換兩個變量的值
a = 1
b = 2
print(a, b)
a, b = b, a
print(a, b)
############## 輸出結(jié)果 ###############
1 2
2 1
看似很簡單的過程,其實中間經(jīng)歷了一個拆包的過程,在pyth里有等號=先看等號右面的內(nèi)容,這里其實是把b和a的數(shù)據(jù)封裝到一個元組里面,然后使用變量a和變量b保存元組里面的第一個值和第二個值。
13. 引用
引用:就是使用的意思, 就是使用變量保存了數(shù)據(jù)在內(nèi)存的地址,變量沒有直接保存數(shù)據(jù),而保存的是數(shù)據(jù)在內(nèi)存中的地址。
num1 = 1:定義一個變量,名稱是num1, 使用該變量保存了一下數(shù)據(jù)1在內(nèi)存中的地址
num2 = num1:定義一個變量,名稱是num2, 使用該變量保存了num1存儲數(shù)據(jù)的內(nèi)存地址
id(num1):使用id()函數(shù)查看變量的內(nèi)存地址。
提示:內(nèi)存地址其實就是一個數(shù)字,可以理解成一個數(shù)字編號
num1 = 1
num2 = num1
print("num1是:", num1, "num2是:", num2)
num1_id = id(num1)
num2_id = id(num2)
print("num1的內(nèi)存地址是:", num1_id, "num2的內(nèi)存地址是:", num2_id)
############## 輸出結(jié)果 ###############
num1是: 1 num2是: 1
num1的內(nèi)存地址是: 140727306383616 num2的內(nèi)存地址是: 140727306383616
我們發(fā)現(xiàn)這兩個變量的內(nèi)存地址是一樣的,說明了賦值其實就是傳遞了數(shù)據(jù)的內(nèi)存地址。
變量重新賦值內(nèi)存地址就是發(fā)生變化:
num1 = 1
num2 = num1
num1 = 2
print(num1, num2)
num1_id = id(num1)
num2_id = id(num2)
print(num1_id, num2_id)
############## 輸出結(jié)果 ###############
2 1
140727223284000 140727223283968
14. 可變類型和不可變類型
不可變類型
不可變類型: 不允許在原有內(nèi)存空間的基礎(chǔ)上修改數(shù)據(jù),修改數(shù)據(jù)后內(nèi)存地址會發(fā)生變化。
不可變類型有: 數(shù)字,字符串,元組
數(shù)字:
num1 = 100
# 查看變量的內(nèi)存地址
num1_id = id(num1)
print(num1, num1_id)
# 不可變類型想要修改數(shù)據(jù),都是通過重新賦值來完成
num1 = 200
# 查看變量的內(nèi)存地址
num1_id = id(num1)
print(num1, num1_id)
############## 輸出結(jié)果 ###############
100 140727306386784
200 140727306389984
字符串:
my_str = "abc"
print(my_str, id(my_str))
my_str = "adc"
print(my_str, id(my_str))
############## 輸出結(jié)果 ###############
abc 2191203856688
adc 2191203947568
元組:
my_tuple = (1, 5)
print(my_tuple, id(my_tuple))
my_tuple = (2, 5)
print(my_tuple, id(my_tuple))
############## 輸出結(jié)果 ###############
(1, 5) 1361982166344
(2, 5) 1361982405960
對于不可變類型來說,不能根據(jù)下標修改數(shù)據(jù),以下操作都是錯誤的操作:
my_str = "abc"
my_str[1] = "d" #這種操作不對,不可變類型不能根據(jù)下標修改數(shù)據(jù)
my_tuple = (1, 5)
my_tuple[0] = 2 #這種操作不對,不可變類型不能根據(jù)下標修改數(shù)據(jù)
總結(jié):
- 對于不可變類型來說,不能在原有內(nèi)存空間的基礎(chǔ)上修改數(shù)據(jù),想要修改數(shù)據(jù)都是通過重新賦值來完成。
- 重新賦值一個新值,那么變量保存的內(nèi)存地址會發(fā)生變化。
可變類型
可變類型:允許在原有內(nèi)存空間的基礎(chǔ)上修改(添加,刪除,修改)數(shù)據(jù),修改后內(nèi)存地址不變。
可變類型: 列表,字典,集合
列表
my_list = [1, 4, 6]
print(my_list)
print(id(my_list))
print("===== 修改數(shù)據(jù)內(nèi)存地址不變 ======")
my_list.append(8)
print(my_list)
print(id(my_list))
############## 輸出結(jié)果 ###############
[1, 4, 6]
1524680118856
===== 修改數(shù)據(jù)內(nèi)存地址不變 ======
[1, 4, 6, 8]
1524680118856
字典
my_dict = {"name": "李四", "age": 20}
print(my_dict)
print(id(my_dict))
print("===== 修改數(shù)據(jù)內(nèi)存地址不變 ======")
my_dict["age"] = 50
print(my_dict)
print(id(my_dict))
############## 輸出結(jié)果 ###############
{'name': '李四', 'age': 20}
2017536906808
===== 修改數(shù)據(jù)內(nèi)存地址不變 ======
{'name': '李四', 'age': 50}
2017536906808
不管是列表還是字典修改數(shù)據(jù)內(nèi)存地址都不會變化,但如果重新賦值那內(nèi)存地址就會發(fā)生變化:
my_list = ["a", "b"]
print(my_list)
print(id(my_list))
print("===== 重新賦值內(nèi)存地址改變 =====")
my_list = ["c", "d"]
print(my_list)
print(id(my_list))
############## 輸出結(jié)果 ###############
['a', 'b']
2441131479624
===== 重新賦值內(nèi)存地址改變 =====
['c', 'd']
2441132757640
總結(jié):
- 在原有內(nèi)存空間的基礎(chǔ)上進行修改數(shù)據(jù),修改后內(nèi)存地址不變
- 重新賦值一個新值,這樣做變量保存的內(nèi)存地址會變化
函數(shù)的可變類型和不可變類型
定義一個函數(shù):
def show(params):
print(params, id(params))
print("==== 修改前VS修改后 ====")
params += params
print(params, id(params))
調(diào)用函數(shù),給函數(shù)傳參的時候,如果params變量是一個不可變類型,那么 += 后 params 保存的內(nèi)存地址會發(fā)生變化,如果 params 變量是一個可變類型,那么 +=后 params 保存的內(nèi)存地址不變,因為可變類型允許在原有內(nèi)存空間的基礎(chǔ)上修改數(shù)據(jù)。
給函數(shù)的參數(shù)傳一個定義可變類型的變量——列表
def show(params):
print(params, id(params))
print("==== 修改前VS修改后 ====")
params += params
print(params, id(params))
# 定義可變類型的變量
my_list = [1, 3]
print(my_list, id(my_list))
#調(diào)用函數(shù)
show(my_list)
############## 輸出結(jié)果 ###############
[1, 3] 2682280956488
[1, 3] 2682280956488
==== 修改前VS修改后 ====
[1, 3, 1, 3] 2682280956488
內(nèi)存地址沒有變化
給函數(shù)的參數(shù)傳一個定義不可變類型的變量——數(shù)字
def show(params):
print(params, id(params))
print("==== 修改前VS修改后 ====")
params += params
print(params, id(params))
# 定義不可變類型的變量
my_num = 1
print(my_num, id(my_num))
# 調(diào)用函數(shù)
show(my_num)
############## 輸出結(jié)果 ###############
1 140727306383616
1 140727306383616
==== 修改前VS修改后 ====
2 140727306383648
內(nèi)存地址改變
15.函數(shù)使用的注意點
return注意點:
- return 只能返回一次數(shù)據(jù);
- 當函數(shù)執(zhí)行了return語句說明函數(shù)執(zhí)行結(jié)束,return語句后面的代碼不能執(zhí)行;
- return關(guān)鍵字只能在函數(shù)或者方法內(nèi)使用
局部變量和全局變量的作用域
- 局部變量的作用域: 只能在函數(shù)內(nèi)部使用;
- 全局變量的作用域: 可以在不同函數(shù)內(nèi)或者函數(shù)外使用
函數(shù)名重名
- 如果函數(shù)名相同,后面的函數(shù)會把前面的同名函數(shù)進行覆蓋,前面的函數(shù)就不能再使用了;
- 在python里面沒有函數(shù)或者方法的重載
def show():
print("明天大家休息,可以出去浪一下~")
def show():
print("浪什么浪,繼續(xù)學(xué)Python!")
show()
############## 輸出結(jié)果 ###############
浪什么浪,繼續(xù)學(xué)Python!
可以看到兩個show()函數(shù)重名,后面的把前面的覆蓋掉了
16. 遞歸函數(shù)
遞歸函數(shù):在一個函數(shù)內(nèi)部又調(diào)用函數(shù)本身那么這樣的函數(shù)稱為遞歸函數(shù)。
遞歸函數(shù)的注意點:遞歸函數(shù)必須要有結(jié)束遞歸調(diào)用條件。
def show(num):
print("人生苦短")
if num == 3:
print("我用Python")
else:
show(num+1)
# 調(diào)用函數(shù)
show(2)
這里 num == 3 就是結(jié)束遞歸的條件,表示不需要再自己調(diào)用函數(shù)本身。
遞歸函數(shù)的應(yīng)用
求某個數(shù)字的階乘
為什么說求數(shù)字的階乘要應(yīng)用到遞歸函數(shù)呢?請看:
3! = 3 * 2 * 1 ---> 3 * 2!
2! = 2 * 1 --- > 2 * 1!
1! = 1
n! = n * (n-1)!
也就是說,我們定義一個計算某一個數(shù)階乘的函數(shù)show(),我們知道 n! = n * (n-1)! 計算n!的過程中需要不斷調(diào)用求階乘的函數(shù)show(),所以就用到遞歸函數(shù)。
def show(num):
if num == 1:
return 1
else:
return num*show(num - 1)
result = show(3)
print(result)
############## 輸出結(jié)果 ###############
6
遞歸調(diào)用擴展:遞歸函數(shù)并不是可以無限次的調(diào)用,系統(tǒng)的默認遞歸調(diào)用次數(shù)是1000次。
查看系統(tǒng)默認遞歸調(diào)用次數(shù):
import sys
count = sys.getrecursionlimit()
print(count)
############## 輸出結(jié)果 ###############
1000
修改默認最大遞歸次數(shù):
# 修改默認遞歸次數(shù)
import sys
sys.setrecursionlimit(2000)
# 查看修改后的結(jié)果
print(sys.getrecursionlimit())
############## 輸出結(jié)果 ###############
2000
17. 匿名函數(shù)
匿名函數(shù):使用
lambda關(guān)鍵字定義函數(shù)稱為匿名函數(shù)。
匿名函數(shù)語法格式:lambda 形參1, 形參2, .... : 返回值或者調(diào)用其他函數(shù)
匿名函數(shù)的注意點:
- 匿名函數(shù)也是屬于函數(shù)的;
- 匿名函數(shù)只能寫一行代碼;
- 匿名函數(shù)的返回值不需要使用return關(guān)鍵字
匿名函數(shù)的使用:
# 使用變量add_func保存了一個匿名函數(shù)
noname_func = lambda num1, num2 : num1 + num2
# 給匿名函數(shù)傳遞參數(shù)
result = noname_func(1, 2)
print(result)
############## 輸出結(jié)果 ###############
3
解釋一下以上匿名函數(shù) lambda num1, num2 : num1 + num2
冒號:前是匿名函數(shù)noname_func的兩個形參,待會兒調(diào)用的時候需要給他們賦值,冒號后面是該函數(shù)的功能:求兩個參數(shù)的和。
在調(diào)用該匿名函數(shù)noname_func(1, 2)時,傳遞了兩個參數(shù)1和2,求兩個參數(shù)的和便是3。
沒有參數(shù)的匿名函數(shù):
no_param = lambda : print("人生苦短,我用Python")
no_param()
############## 輸出結(jié)果 ###############
人生苦短,我用Python
學(xué)習(xí)匿名函數(shù)目的:使用匿名函數(shù)可以簡化普通函數(shù)的代碼。
18. 列表推導(dǎo)式
列表推導(dǎo)式: 使用for循環(huán)快速創(chuàng)建一個列表,也就是說列表推導(dǎo)式最終返回的類型是列表。
語法結(jié)構(gòu):[xx for xx in 容器類型]
使用for循環(huán)快速創(chuàng)建列表
使用for循環(huán)快速創(chuàng)建列表即列表推導(dǎo)式,示例:
result = [value for value in range(1, 6)]
print(result, type(result))
############## 輸出結(jié)果 ###############
[1, 2, 3, 4, 5] <class 'list'>
列表推導(dǎo)式代碼解釋:for循環(huán)可以使value遍歷range(1, 6)(即,[1, 5])里的每一個元素,給for前面的value,生成一個列表。
列表推導(dǎo)式結(jié)合if語句
列表推導(dǎo)式可以結(jié)合if語句使用,作為條件過濾對應(yīng)的數(shù)據(jù),比如我們只要1-10之間所有的奇數(shù):
result = [value for value in range(1, 11) if value % 2 == 1]
print(result, type(result))
############## 輸出結(jié)果 ###############
[1, 3, 5, 7, 9] <class 'list'>
列表推導(dǎo)式結(jié)合if語句代碼解釋:for循環(huán)使value遍歷range(1, 11)中的每一個元素(即:[1, 10])然后if語句對for循環(huán)遍歷的每一個元素進行過濾——是否滿足if后面的條件,這里就是查看1-10中的每一個數(shù)字除以2后是否余數(shù)是1,把滿足條件的元素賦值給for前面的value然后生成一個列表。
列表推導(dǎo)式結(jié)合多個for循環(huán)使用
result = [(value1, value2) for value1 in range(2) for value2 in range(1, 4)]
print(result, type(result))
############## 輸出結(jié)果 ###############
[(0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3)] <class 'list'>
列表推導(dǎo)式結(jié)合多個for循環(huán)代碼解釋: value1遍歷 range(2)(即0、1),value2遍歷 range(1, 4)(即,1、2、3)給前面的元組(value1, value2),value1和value2組合成的所有元組生成一個列表輸出。
練一練1:使用列表推導(dǎo)式取出
my_list列表里年齡大于20歲的
my_list = [{"name": "李四", "age": 20}, {"name": "王五", "age": 22}]
result = [my_dict for my_dict in my_list if my_dict["age"] > 20]
print(result)
############## 輸出結(jié)果 ###############
[{'name': '王五', 'age': 22}]
練一練1的代碼解釋: 我們創(chuàng)造一個任意變量my_dict使for循環(huán)遍歷已知列表my_list里面的每一個元素,這里的元素就是兩個字典,然后if語句會判斷這每一個元素是否符合條件,然后把符合條件的給for前面的變量然后生成一個列表輸出。
練一練2:使用已知列表
my_list = ["A", "B", "C"]和列表推導(dǎo)式生成一個新列表new_list = ["AAA", "BBB", "CCC"]
my_list = ["A", "B", "C"]
result = [value * 3 for value in my_list]
print(result)
############## 輸出結(jié)果 ###############
['AAA', 'BBB', 'CCC']
練一練2的代碼解釋: for循環(huán)遍歷了已知列表my_list里的每一個元素(A、B、C),然后將這每個元素賦值給for前面的變量value再進行乘法*運算操作后生成列表返回。
練一練3:使用已知列表
my_list = ["A", "B", "C"]和列表推導(dǎo)式生成一個新列表new_list = ["A!", "B!", "C!"]
my_list = ["A", "B", "C"]
result = [value + "!" for value in my_list]
print(result)
############## 輸出結(jié)果 ###############
['A!', 'B!', 'C!']
練一練3的代碼解釋: for循環(huán)遍歷了已知列表my_list里的每一個元素(A、B、C),然后將這每個元素賦值給for前面的變量value再進行加法+運算操作后生成列表返回。
19. 集合
集合(set): 也是一個容器類型,可以存儲多個數(shù)據(jù),但是集合里面的數(shù)據(jù)不能重復(fù)。
學(xué)習(xí)集合目的:以后可以通過集合對容器類型數(shù)據(jù)進行去重
集合特點:
- 數(shù)據(jù)不能重復(fù)
- 集合也是一個可變類型
- 集合里面的數(shù)據(jù)是無序的—“無序”的意思就是,我們定義一個集合每次的輸出順序都不一樣。
定義集合
my_set = {1, 3, "A", "b"}
print(my_set, type(my_set), id(my_set))
############## 輸出結(jié)果 ###############
{1, 'A', 3, 'b'} <class 'set'> 2132515827272
因為集合里面的數(shù)據(jù)是無序的所以我們可以看出,輸出的集合里的數(shù)據(jù)順序和我們定義的順序并不一致。
添加數(shù)據(jù)
使用my_set.add(2)添加數(shù)據(jù)
my_set = {1, 3, "A", "b"}
print(my_set, type(my_set), id(my_set))
my_set.add(2)
print(my_set, type(my_set), id(my_set))
############## 輸出結(jié)果 ###############
{1, 'A', 3, 'b'} <class 'set'> 2266825698888
{1, 2, 3, 'b', 'A'} <class 'set'> 2266825698888
我們發(fā)現(xiàn),向集合添加數(shù)據(jù)后,集合的id地址并沒有發(fā)生變化,所以說集合也是一個可變類型。
知道如何向集合里面添加數(shù)據(jù)后,我們向集合里添加一個集合里本來就存在的數(shù)據(jù),來驗證一下集合里的數(shù)據(jù)不能重復(fù):
my_set = {1, 3, "A", "b"}
print(my_set)
my_set.add("A")
print(my_set)
############## 輸出結(jié)果 ###############
{1, 'b', 3, 'A'}
{1, 'b', 3, 'A'}
我們可以看到向集合里添加一個集合里本來就有的數(shù)據(jù)"A"后,輸出并沒有變化。我們常常使用集合里面的數(shù)據(jù)不能重復(fù)這一特性來對其他容器類型進行去重操作。
空集合的寫法 — set()
空的集合不能直接使用大括號,大括號表示字典。
錯誤演示:
my_set = {}
print(my_set, type(my_set))
############## 輸出結(jié)果 ###############
{} <class 'dict'>
我們可以看到,空集合如果直接用大括號定義,輸出的類型是一個字典dict。
定義空集合正確演示:
my_set = set()
print(my_set, type(my_set))
############## 輸出結(jié)果 ###############
set() <class 'set'>
向空集合中添加數(shù)據(jù):
print("==== 定義一個空集合 ======")
my_set = set()
print(my_set, type(my_set))
print("=== 空集合中添加數(shù)據(jù):=====")
my_set.add(1)
print(my_set, type(my_set))
############## 輸出結(jié)果 ###############
==== 定義一個空集合 ======
set() <class 'set'>
=== 空集合中添加數(shù)據(jù):=====
{1} <class 'set'>
注意點:因為集合是無序的所以不能根據(jù)下標獲取和修改數(shù)據(jù)。
不能根據(jù)下標獲取數(shù)據(jù)的報錯演示:
my_set = {1, 3, "A", "b"}
print(my_set[1])
############## 輸出結(jié)果 ###############
TypeError: 'set' object is not subscriptable
不能根據(jù)下標修改數(shù)據(jù)的報錯演示:
my_set = {1, 3, "A", "b"}
my_set[2] = "C"
############## 輸出結(jié)果 ###############
TypeError: 'set' object does not support item assignment
集合里面只能存放不可變類型數(shù)據(jù)(字符串,數(shù)字,元組),不能存放可變類型數(shù)據(jù)。
集合里如果存放列表等可變類型的數(shù)據(jù)就會報錯:
my_set = {1, "A", (1, 2), [1, 2]}
print(my_set)
############## 輸出結(jié)果 ###############
TypeError: unhashable type: 'list'
集合的拆包:
value1, value2, value3 = {1, 3, "A"}
print(value1, value2, value3)
############## 輸出結(jié)果 ###############
1 3 A
遍歷集合:
for value in {1, 3, "A"}:
print(value)
############## 輸出結(jié)果 ###############
1
3
A
使用set對容器中的數(shù)據(jù)進行去重:
我們常常使用集合里面的數(shù)據(jù)不能重復(fù)這一特性來對其他容器類型進行去重操作。
需求:對已知列表
my_list = [1, 1, 2, 4]去重。
思路:把已知列表轉(zhuǎn)成集合(set) ---> 把集合再轉(zhuǎn)成列表
列表轉(zhuǎn)換成集合后會自動對列表里面的數(shù)據(jù)去重,再把該集合轉(zhuǎn)換回列表。
my_list = [1, 1, 2, 4]
# 把列表轉(zhuǎn)成集合(set)
new_set = set(my_list)
print(new_set)
# 把集合再轉(zhuǎn)成列表
new_list = list(new_set)
print(new_list)
############## 輸出結(jié)果 ###############
{1, 2, 4}
[1, 2, 4]
需求:對已知元組
my_tuple = (1, 22, 1, 33)去重。
與上面列表的去重操作完全一樣:
my_tuple = (1, 22, 1, 33)
# 把元組轉(zhuǎn)成集合
new_set = set(my_tuple)
print(new_set)
# 把集合轉(zhuǎn)成元組
new_tuple = tuple(new_set)
print(new_tuple)
############## 輸出結(jié)果 ###############
{1, 22, 33}
(1, 22, 33)
20.高階函數(shù)
高階函數(shù):函數(shù)的參數(shù)或者返回值是一個函數(shù)類型,那么這樣的函數(shù)稱為高階函數(shù)
高階函數(shù) — 函數(shù)的參數(shù)是函數(shù)類型
def show(new_func): # 此時new_func參數(shù)就是一個函數(shù)類型
num1 = 1
num2 = 2
# 調(diào)用輸入過來的函數(shù)
result = new_func(num1, num2)
print("顯示結(jié)果:", result)
# 此時調(diào)用show函數(shù)時,傳入一個匿名函數(shù)。
show(lambda x, y: x - y)
############## 輸出結(jié)果 ###############
顯示結(jié)果: -1
show()函數(shù)括號里面的參數(shù)是一個函授,這就是一個高階函數(shù)。調(diào)用show()函數(shù)時先回到定義函數(shù)的地方,一步一步往下執(zhí)行。
高階函數(shù) — 函數(shù)返回值是一個函數(shù)類型
def show_info():
# 定義子函數(shù)
def inner_func():
print("我是一個子函數(shù)或者內(nèi)部函數(shù)")
# 調(diào)用內(nèi)部函數(shù)
# inner_func()
return inner_func # 返回一個函數(shù),函數(shù)名是inner_func
# return inner_func()# 返回是一個函數(shù)調(diào)用后的結(jié)果 inner_func() = 》 None
new_func = show_info()
new_func()
############## 輸出結(jié)果 ###############
我是一個子函數(shù)或者內(nèi)部函數(shù)
python提供的高階函數(shù)
python提供的高階函數(shù)-reduce
reduce: 根據(jù)提供的功能函數(shù)對容器類型中每一個數(shù)據(jù)進行相關(guān)計算
import functools # 函數(shù)工具模塊
# reduce: 根據(jù)提供的功能函數(shù)對容器類型中每一個數(shù)據(jù)進行相關(guān)計算
my_list = ["A", "B", "C"]
# 定義功能函數(shù)
def calc_str(my_str1, my_str2):
return my_str1 + my_str2
# 1. 提供的功能函數(shù)
# 2. 要計算的容器類型
result = functools.reduce(calc_str, my_list)
print(result, type(result))
############## 輸出結(jié)果 ###############
ABC <class 'str'>
應(yīng)用:計算1-100之間的累加和
import functools # 函數(shù)工具模塊
new_list = [value for value in range(1, 101)]
print(new_list)
# 提示:匿名函數(shù)以后都是結(jié)合高階函數(shù)去使用
# functools.reduce(匿名函數(shù), new_list)
result = functools.reduce(lambda x, y: x + y, new_list)
print(result)
############## 輸出結(jié)果 ###############
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
5050
合并簡寫版:
# 提示:函數(shù)如果結(jié)合reduce高階函數(shù)使用,那么提供函數(shù)的參數(shù)必須有兩個
import functools # 函數(shù)工具模塊
result = functools.reduce(lambda x, y: x + y, range(1, 101))
print(result)
############## 輸出結(jié)果 ###############
5050
python提供的高階函數(shù)-filter高階函數(shù)
filter高階函數(shù)所需要的功能函數(shù),功能函數(shù)的參數(shù)只有一個
my_list = [1, 3, 5, 10, 11, 20]
def my_filter(value):
return value % 2 == 1
new_filter = filter(my_filter, my_list)
print(new_filter)
# 把過濾結(jié)果轉(zhuǎn)成列表
result = list(new_filter)
print(result)
############## 輸出結(jié)果 ###############
<filter object at 0x00000220F4FAC388>
[1, 3, 5, 11]
簡化后的寫法:
my_list = [1, 3, 5, 10, 11, 20]
new_filter = filter(lambda x: x % 2 == 1, my_list)
result = list(new_filter)
print(result)
############## 輸出結(jié)果 ###############
[1, 3, 5, 11]
練習(xí):過濾出my_list里年齡大于20歲的學(xué)生信息
my_list = [{"name": "李四", "age": 20}, {"name": "王四", "age": 22}]
my_list = [{"name": "李四", "age": 20}, {"name": "王四", "age": 22}]
new_filter = filter(lambda my_dict: my_dict["age"] > 20, my_list)
result = list(new_filter)
print(result)
############## 輸出結(jié)果 ###############
[{'name': '王四', 'age': 22}]