Python基礎(chǔ)Day5/6—函數(shù)和集合

問:為什么總是把簡書筆記寫的那么長這樣沒人看的
其實我在簡書上記筆記只是方便我日后想不起來的時候 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)容,這里其實是把ba的數(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),value1value2組合成的所有元組生成一個列表輸出。

練一練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}]
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容