1. 程式人生 > 實用技巧 >我的python學習之路-基礎3

我的python學習之路-基礎3

本文內容:

  1. 檔案操作
  2. 函式
  3. 高階函式
  4. locals() 和 globals()
  5. 迭代器
  6. 高階函式

 

一 .檔案操作

對檔案操作流程

  1. 開啟檔案,得到檔案控制代碼並賦值給一個變數
  2. 通過控制代碼對檔案進行操作
  3. 關閉檔案

檔案內容可以寫入:1.位元組流 2.字串

1.基本操作

# 1.開啟檔案
fp = open("lianxi.txt",mode="w",encoding="utf-8") 
# 2.寫入檔案
fp.write("把大象塞進去") 
# 3.關閉檔案
fp.close() 
# 1.開啟檔案
fp = open("lianxi.txt",mode="r",encoding="
utf-8") # 2.讀取檔案 res = fp.read() # 3.關閉檔案 fp.close() print(res)

2.位元組流操作

二進位制位元組流的應用場景: 在資料傳輸或者在資料儲存時,使用的一種資料格式;
多個字元放在一起叫做字串,多個位元組放在一起叫做位元組流;

將字串和位元組流(Bytes流)型別進行轉換 (引數寫成轉化的字元編碼格式)
encode() 編碼 :將字串轉化為位元組流(Bytes流)
decode() 解碼 :將Bytes流轉化為字串

位元組流的格式:位元組流語法格式(前面加b) : b"123"

strvar = b"123"
strvar = b"
abc" # 中文不能在字串前面加b,必須是ascii編碼才能加; # strvar = b"你好" error print(strvar , type(strvar)) # b'123' <class 'bytes'>

中文和位元組流的轉化

# encode 編碼
strvar = "我愛你".encode("utf-8")
print(strvar)

# decode 解碼
res = strvar.decode("utf-8")
print(res)

# 三個位元組表達一箇中文字元
s_bytes = b'\xe7\x88\xb1'
res = s_bytes.decode("
utf-8") print(res)

檔案中寫入位元組流

"""mode = wb 代表寫入的是位元組流 , 不要指定任何編碼集 """
# 1.開啟檔案
fp = open("lianxi2",mode="wb")
strvar = "愛上一匹野馬,家裡沒有草原"
# 2.寫入位元組流
fp.write(strvar.encode())
# 3.關閉檔案
fp.close()

從檔案中讀位元組流

"""mode = rb 代表讀取的是位元組流 , 不要指定任何編碼集 """
# 1.開啟檔案
fp = open("lianxi2",mode="rb")
# 2.讀取位元組流
res = fp.read()
# 3.關閉檔案
fp.close()
print(res)
print(res.decode())

小例子:模擬複製圖片的過程

 1 # 開啟原檔案,讀取其中的位元組流
 2 fp = open("集合.png",mode="rb")
 3 res = fp.read()
 4 fp.close()
 5 print(res)
 6 
 7 # 把這些位元組流寫入到另外檔案中
 8 fp = open("集合2.gif",mode="wb")
 9 fp.write(res)
10 fp.close()
View Code

總結: 二進位制位元組流比如:圖片,音訊,視訊 ... 資料使用二進位制位元組流進行拷貝

3.檔案的擴充套件模式

read() 功能: 讀取字元的個數(裡面的引數代表字元個數)

seek() 功能: 調整指標的位置(裡面的引數代表位元組個數)

  seek(0) 把游標移動到檔案開頭

  seek(0,2) 把游標移動到檔案末尾

tell() 功能: 當前游標左側所有的位元組數(返回位元組數)

1..r+ 先讀後寫
fp = open("lianxi.txt",mode="r+",encoding="utf-8")
# 先讀
res = fp.read()
# 後寫
fp.write("456")
# 在讀
fp.seek(0) #因為檔案指標在檔案末尾,指向開頭
res = fp.read()
print(res)
fp.close()
2.r+ 先寫後讀

r+模式開啟後 檔案指標預設指向檔案的開頭,馬上寫入內容,會覆蓋原有的內容

fp = open("lianxi.txt",mode="r+",encoding="utf-8")
# 先寫
fp.seek(0,2) # 開啟檔案後預設指向檔案開頭
fp.write("789")
# 後讀
fp.seek(0)
res = fp.read()
print(res)
fp.close()
3.w+ 可寫可讀

w+模式開啟檔案後,首先預設清空檔案,所以先讀後寫沒有意義;

fp = open("lianxi2.txt",mode="w+",encoding="utf-8")
# 先寫
fp.write("123")
# 後讀
fp.seek(0)
print(fp.read())
fp.close()
4.a+ 可寫可讀

a+模式開啟後 檔案指標預設指向檔案的末尾,所以可以直接寫入內容

fp = open("lianxi3.txt",mode="a+",encoding="utf-8")
fp.write('abc')
fp.seek(0)
print(fp.read())
fp.close()
5.比對a+和r+兩個模式之間的區別

r+模式下 寫入內容時,會隨著游標位置的改變而替換原有的字元

a+模式下 寫入內容時,會強制把游標移動到檔案的末尾

 

6.seek ,read , tell 三個方式的使用

read(單位) 單位根據檔案開啟的模式而產生變化,如果帶有b模式,讀取的是位元組的個數,否則讀取的是字元的個數

在移動seek時,小心游標移動到中文字元裡,在讀取內容時,產生無效的開始位元組

fp = open("lianxi.txt",mode="r+",encoding="utf-8")
fp.seek(6)
res = fp.tell() #6
print(res)
res = fp.read(3)
print(res)
res = fp.tell()
print(res)
fp.close()
7. with語法 (上下文管理器)可以省略掉close操作
with open("ceshimv.mp4",mode="rb") as fp1 , open("ceshimv2.mp4",mode="wb") as fp2:
    res = fp1.read()
    fp2.write(res)

3.檔案相關的方法

1.重新整理緩衝區 flush

重新整理緩衝區有一下幾種情況

  (1). 當檔案關閉的時候自動重新整理緩衝區
  (2).當整個程式執行結束的時候自動重新整理緩衝區
  (3)當緩衝區寫滿了 會自動重新整理緩衝區
  (4)手動重新整理緩衝區

 

2.檔案相關函式

 1.readable() 功能: 判斷檔案物件是否可讀
 2.writable() 功能: 判斷檔案物件是否可寫
 3.readline() 功能 :讀取檔案一行內容

(1) .先讀取一行,如果內容不是空,列印這行資料,在讀取下一行進行判斷 

with open("lianxi.txt",mode="r",encoding="utf-8") as fp:
    res = fp.readline()
    while res:
        print(res)
        res = fp.readline()

(2).readline(2) 2個字元個數

如果讀取個數 > 當前行總個數 : 按照當前行讀取
如果讀取個數 < 當前行總個數 : 按照個數讀取

4.readlines 功能:將檔案中的內容按照換行讀取到列表當中
5.writelines() 功能:將內容是字串的可迭代性資料寫入檔案中 引數:內容為字串型別的可迭代資料
6.truncate() 功能: 把要擷取的字串提取出來,然後清空內容將提取的字串重新寫入檔案中 (位元組)
with open("lianxi4.txt",mode="r+",encoding="utf-8") as fp:
    fp.truncate(9)

二.函式

1.函式基本格式

定義函式
def 函式名():
    code1
    code2...
呼叫函式
函式名()

2.函式的命名

字母數字下劃線,首字元不能為數字;

嚴格區分大小寫,且不能使用關鍵字;
函式命名有意義,且不能使用中文哦;

1.駝峰命名法:

  (1)大駝峰命名法:mycar => MyCar每個單詞首字元大寫 (面向物件中 => 類)

  (2)小駝峰命名法: mycar => myCar除了第一個單詞首字元小寫外,剩下的每個單詞首字元大寫 (用在函式中 .. )

2.命名法: 單詞和單詞之間用_分開 mycar => my_car

3.函式的引數

函式的引數的種類: 1.形參 2.實參

1.形參: 形式上的引數,在函式的定義處

2.實參: 實際上的引數,在函式的呼叫處

形參種類: 1.普通形參(位置形參) 2.預設形參 3.普通收集形參 4.命名關鍵字形參 5 關鍵字收集形參

實參種類: 1.普通實參 2.關鍵字實參

1.普通形參

"""hang,lie是普通形參(位置形參)"""
def func(hang,lie):
    i = 0
    while i < hang:
        j = 0
        while j < lie :
            print("*" ,end="")
            j += 1
        print()
        i += 1
# 呼叫函式
"""10,10是普通實參"""
func(10,10)
func(3,8)

2.預設形參

hang=10,lie=10 是預設形參,如果給與了實參,那麼使用實參值,如果沒有給與實參,那麼使用預設值

def func(hang=10,lie=10):
    i = 0
    while i < hang:
        j = 0
        while j < lie :
            print("*" ,end="")
            j += 1
        print()
        i += 1
        
# 呼叫函式
# func()
func(5)
# func(4,6)

3.普通形參 + 預設形參

hang普通形參,lie=10預設形參

注意點:預設形參必須跟在普通形參的後面

def func(hang,lie=10):
    i = 0
    while i < hang:
        j = 0
        while j < lie :
            print("*" ,end="")
            j += 1
        print()
        i += 1
# func(5)
func(5,6)

4.關鍵字實參

關鍵字實參的順序可以任意顛倒

注意點: 關鍵字實參必須寫在普通實參的後面

def func(hang,a,b,c,lie=10):
    i = 0
    while i < hang:
        j = 0
        while j < lie :
            print("*" ,end="")
            j += 1
        print()
        i += 1
func(3,4,b=5,lie=7,c=6)    

區別關鍵字實參和預設形參:

1.在def定義處,使用的引數是預設形參

2.在函式的呼叫處,使用的引數是關鍵字實參

5.普通收集引數

功能: 專門用來收集那些多餘的沒人要的普通實參

語法: 在引數的前面加上一顆星

返回: 一個元組

def func(a,b,c,*args):
    print(a,b,c) #1 2 3
    print(args) # (43,44)
func(1,2,3,43,44)

計算任意個數值的累加和

1 def func(*args):
2     print(args) # (1, 2, 3, 4, 5, 6, 7)
3     total = 0 
4     for i in args:
5         total += i
6     print(total)
7 
8 func(1,2,3,4,5)
View Code

6.關鍵字收集引數

  功能: 專門用來收集那些多餘的沒人要的關鍵字實參

語法: 在引數的前面上加上二顆星星

返回: 一個字典

def func(a,b,c,**kwargs):
    print(a,b,c) # 1 4 3
    print(kwargs) #{'f': 5, 'z': 10, 'x': 30}
func(a=1,c=3,f=5,b=4,z=10,x=30)

做任意個數值的字串拼接

 1 """
 2 顏值擔當: 李雅琪
 3 靚麗女生: 王永捐
 4 普通顏值: 於盛林, 荷葉 , 吳洪昌
 5 """
 6 
 7 def func(**kwargs):
 8     strvar1 = ''
 9     strvar2 = ''
10     dic = {"beautiful_boy":"顏值擔當" , "beautiful_girl":"靚麗女生"}
11     print(kwargs) # {'beautiful_boy': '李雅琪', 'beautiful_girl': '王永捐', 'common1': '於盛林', 'common2': '荷葉', 'common3': '吳洪昌', 'first': '菲菲', 'last': '石磊'}
12     for k,v in kwargs.items():
13         # print(k,v)
14         # 如果該鍵在dic當中,說明是預定義角色,要獲取該角色是什麼 : 顏值擔當   靚麗女生
15         if k in dic:
16             # 顏值擔當 : 李雅琪 + '\n'
17             # 靚麗女生 : 王永捐 + '\n'
18             strvar1 += dic[k] + ":" + v + '\n'
19         else:
20             # 於盛林, 荷葉, 吳洪昌, 菲菲, 石磊,
21             strvar2 += v + ","  
22     
23     
24     print(strvar1.strip())
25     print(  "普通顏值:"  ,  strvar2.strip(",")   )
26     
27 func(beautiful_boy = "李雅琪",beautiful_girl="王永捐",common1="於盛林",common2="荷葉",common3="吳洪昌",first="菲菲",last="石磊")
View Code

7命名關鍵字形參

如果是命名關鍵字形參 , 在呼叫函式時,必須使用關鍵字實參的方式呼叫

(1) def func(a,b,*,c,d) 在星號後面定義的是命名關鍵字形參

def func(a,b,*,c,d):
    print(a,b)
    print(c)
    print(d)
func(1,2,c=3,d=4)

(2) def func(*args,c,**kwargs) 在普通收集和關鍵字收集形參之間的是命名關鍵字形參

print("<=========>")
def func(*args,c,**kwargs):
    print(args)
    print(c)
    print(kwargs)
func(1,2,3,4,45,a=1,b=2,c=3)

8.* 和 ** 的使用方法

(1) 在定義處: 負責收集打包資料
  * : 負責收集打包成元組
  **: 負責收集打包成字典
(2) 在呼叫處: 負責打散解包資料
  * : 負責對list tuple str set 打散解包成單獨的資料
  **: 負責對dic 打散解包成單獨的鍵=值的形式

# 函式的定義處
def func(a,b,*,c,d):
    print(a,b)
    print(c,d)
lst = [1,2] # 打散之後,把列表裡面的元素一個個拿出來作為函式的引數進行呼叫
tup = (1,2)
set1 = {"aaa","bbb"}
str1 = "ab" 
dic = {"aaaa":1,"bbbb":2} # 獲取的是字典的鍵
# 函式的呼叫處 一顆星  *可迭代資料前面
func(*dic,c=3,d=4) # func(1,2,c=3,d=4)
# 函式的呼叫處 二顆星 **只能在字典前面修飾;
dic = {"c":3,"d":4}
func(1,2,**dic) # 把字典打散,抽離其中的鍵值對,變成 => c=3,d=4 關鍵字實參,作為引數呼叫函式;

函式的引數定義順序:
普通形參(位置形參) => 預設形參 => 普通收集形參 -> 命名關鍵字形參 -> 關鍵字收集形參;

4.return

return : 會把函式內部的值返回到函式的呼叫處;

(1)return後面可以接 6大標準資料型別 ,還可以接函式,類,物件,如果沒有自定義返回值,預設返回的None
(2)執行完return之後,函式直接終止,後面的程式碼不執行;

5.全域性變數 和 區域性變數

區域性變數: 在函式內部定義的變數是區域性變數

全域性變數: 在函式外部或者在函式內部使用global定義的變數是全域性變數

作用域: 作用的範圍

  區域性變數: 在函式的內部
  全域性變數: 橫跨整個檔案

生命週期:變數存活的時間

  內建變數 > 全域性變數 > 區域性變數

1.區域性變數

def func():
    # 建立一個區域性變數
    a = 1
    # 獲取區域性變數
    print(a)
    # 修改一個區域性變數
    a = 10
    print(a)
func()
# print(a) error

2.全域性變數

方法一 :在函式外部定義的是全域性變數

# 建立一個全域性變數
b = 100
# 獲取全域性變數
print(b)
# 修改全域性變數
b = 299
print(b)

def func():
    # 全域性變數可以直接在函式內部呼叫
    print(b)
func()

方法二: 在函式內部定義全域性變數,依賴global

def func():
    # 宣告一個全域性變數c
    global c
    # 建立一個全域性變數
    c = 99
func()
print(c)
# 在函式內部修改全域性變數
d = 200
def func():
    global d
    d = 300
func()
print(d) #300

global總結:
如果函式外部沒有該全域性變數,那麼可以通過global在函式內部直接建立一個全域性變數
如果函式外部有該全域性變數,那麼可以通過global在函式內部修改當前全域性變數

6.函式名的使用

python中的函式可以像變數一樣,動態建立,銷燬,當引數傳遞,作為值返回,作為容器中的元素.叫第一類物件.其他語言功能有限

 1 # 1.動態建立
 2 def func():
 3     print("我是func1 ... ")
 4 print(type(func))
 5 a = 1
 6 print(type(a))
 7 a = func
 8 a()
 9 
10 # 2.動態銷燬
11 del a
12 # a() error
13 # func()
14 
15 # 3.當引數傳遞
16 def func1(f):
17     f()
18 
19 def func2():
20     print("我是func2 ... ")
21     
22 func1(func2)
23 
24 # 4.作為值返回
25 def func1(f):
26     return f
27 
28 def func3():
29     print("我是func3 ...")
30 res = func1(func3)
31 res()
32 
33 # 5.可以把函式作為容器中的元素
34 def func1():
35     print("我是func1 .. ")
36 def func2():
37     print("我是func2 .. ")
38 def func3():
39     print("我是func3 .. ")
40 lst = [func1,func2,func3]
41 for i in lst:
42     i()
43 
44 
45 # ### __doc__ 用來檢視幫助文件
46 def wash(something):
47 
48     """
49 功能: 洗衣服的過程
50 引數: something => 衣服
51 返回值: 洗完的狀態
52     """
53 
54     print( "先脫{}".format(something) )
55     print("放在桶裡")
56     print("到點洗衣液")
57     print("泡水,搓一搓")
58     print("穿上~")
59     return "洗完了"
60     
61 wash("衣服")
62 
63 # __doc__ 函式.__doc__ 獲取函式內部自定義文件;
64 res = wash.__doc__
65 print(res)
View Code

7.函式的巢狀

互相巢狀的兩個函式:
  外層函式即外函式
  內層函式即內函式

def outer():
    inner()
    def inner():
        print("我是內函式 ... ")

(1)內部函式不可以直接在函式外部呼叫
(2)呼叫外部函式後,內部函式不可以在函式外部呼叫

(3)內部函式可以在函式內部呼叫嗎

(4)內部函式在函式內部呼叫時,必須先定義函式,在呼叫函式,沒有預載入機制


三層函式巢狀,最外層是outer,中間層是inner ,最裡層 smaller , 呼叫smaller函式

def outer():    
    def inner():
        def smaller():            
            print("我是smaller函式 ... {}".format(id))
        smaller()
    inner()    
outer()
print(outer)

LEGB 就近找變數原則:
找尋變數的呼叫順序採用LEGB原則(即就近原則)
B —— Builtin(Python);Python內建模組的名稱空間 (內建作用域)
G —— Global(module); 函式外部所在的名稱空間 (全域性作用域)
E —— Enclosing function locals;外部巢狀函式的作用域(巢狀作用域)
L —— Local(function);當前函式內的作用域 (區域性作用域)
依據就近原則,從下往上 從裡向外 依次尋找

8.nonlocal (修改區域性變數)

nonlocal 專門用來修改區域性變數,符合LEGB原則,就近找變數,

(1).找當前作用域上一層空間的變數值進行修改

def outer():
    a = 1
    def inner():
        nonlocal a
        a = 10
        print(a) #10
    inner()
    print(a) #10
outer() 

(2).如果上一層不存在,繼續向上一層空間進行尋找

def outer():
    a = 199
    def inner():
        a = 201
        def smaller():
            nonlocal a
            a  = 200
            print(a) #200
        smaller()
        print(a) #200
    inner()
    print(a) #199
outer()

(3).直到最後找不到,直接報錯

a = 199 # 是全域性變數, 而nonlocal用來修改區域性變數;
def outer():
    def inner():
        def smaller():
            nonlocal a
            a  = 200
            print(a)
        smaller()
        print(a)
    inner()
    print(a)
outer()

不通過 nonlocal 可以修改區域性變數

def outer():
    lst = [10,20,30]
    def inner():
        lst[0] = 100
    inner()
    print(lst) #[100, 20, 30]
outer()

9、閉包函式

互相巢狀的兩個函式,內函式使用了外函式的區域性變數,

外函式把內函式返回出來的過程,叫閉包,內函式叫做閉包函式

原則:
(1) 內函式使用了外函式的區域性變數
(2) 外函式將內函式返回return

1.閉包函式基本語法

def liyaqi_family():
    father = "李嘉誠"
    def hobby():
        print("我對錢沒有興趣,我只對捐錢感興趣,這是我爸爸{}說的".format(father))    
    return hobby 
res = liyaqi_family()
res()

2.閉包的複雜語法

 1 def liangruiqing_family():
 2     jiejie = "馬蓉"
 3     meimei = "馬諾"
 4     money = 1000
 5     
 6     def jiejie_hobby():
 7         nonlocal money
 8         money -= 600
 9         print("喜歡出軌,喜歡花錢,喜歡買包包,手錶,GUCCI,chanel...家裡的錢敗光了,還剩下{}".format(money))
10     
11     def meimei_hobby():
12         nonlocal money
13         money -= 399
14         print("我就喜歡在寶馬裡面哭,不喜歡在自行車上面撒歡~...家裡的錢敗光了,還剩下{}".format(money))
15     
16     def big_master():
17         return [jiejie_hobby,meimei_hobby]
18     
19     # def func():
20         # print(jiejie)
21     # return func
22     
23     return big_master
24 
25 
26 func = liangruiqing_family()
27 # 獲取姐姐函式
28 jiejie = lst[0]
29 jiejie() #家裡的錢敗光了,還剩下400
30 # 獲取妹妹函式
31 meimei = lst[1]
32 meimei() 家裡的錢敗光了,還剩下1
View Code

3.閉包的特點

互相巢狀的兩個函式形成了閉包;內函式使用了外函式的區域性變數,
該變數與內函式發生繫結,延長該變數的生命週期,直到該指令碼執行結束.

def outer(val):
    def inner(num):
        return val + num
    return inner
func = outer(10)
res = func(5)
print(res) #15

4.閉包的意義

在做計數加1的過程當中,發現全域性變數的值範圍太大,導致可以被任意篡改,資料不安全

clicknum = 0
def func():
    global clicknum
    clicknum += 1
    print(clicknum)
func()
func()
func()
clicknum = 100
func() #101

出現的問題:單純的區域性變數不能累加1,

def clicknum():
    x = 0
    x += 1
    print(x)
clicknum()
clicknum()
clicknum()

閉包的意義:

閉包可以優先使用外函式中的變數,並對閉包中的值起到了封裝保護的作用.外部無法訪問

def clicknum():
    x = 0
    def func():
        nonlocal x
        x += 1
        print(x)
    return func
func = clicknum() # func = 閉包函式func
func()
func()
x = 100
func() #3

10.匿名函式

用一句話來表達只有返回值的函式叫做匿名函式

語法: lambda 引數 : 返回值

(1)無參的匿名函式

def func():
    return "我是func1111"
res = func()
print(res)

# lambda 改造
func = lambda : "我是func1111"
print(func())

(2) 有參的匿名函式

def func(num):
    return type(num)
res = func([1,2,3])
print(res)

# lambda 改造
func = lambda num :  type(num)
print(func({"a":"1",'b':2}))

(3) 帶有判斷條件的匿名函式

三元(目)運算子 (只能在雙向分支上可以使用,單項多項都不行)
語法: 真值 if 條件表示式 else 假值 => 如果條件表示式是真的,返回真值,否則返回假值

def func(num):
    if num % 2 == 0:
        return "偶數"
    else:
        return "奇數"
res = func(11)
print(res)

# lambda 改造
print("<=================>")
func = lambda num : "奇數" if num % 2 == 1 else "偶數"
print(func(102))

三.locals() 和 globals()

1.locals() 獲取當前作用域的變數

  在函式外,獲取的是列印之前所有全域性變數

  在函式內,獲取的是呼叫之前所有區域性變數

# 1.在函式外
a = 1
b = 2
dic = locals()
c = 3
print(dic)  #a b c 都要列印 
# 2.在函式內

def func():
    a = 1
    b = 2
    dic = locals()
    c = 3
    print(dic)
    d = 4
f = 5
func() # #列印 a b
g = 6

2 . globals() 獲取全域性變數

在函式外,獲取的是列印之前所有全域性變數
在函式內,獲取的是呼叫之前所有全域性變數

# 1.在函式外
a = 1
b = 2
dic = globals()
c = 3
print(dic) ## a b c 都要列印
# 2.在函式內

def func():
    a = 1
    b = 2
    dic = globals()
    c = 3
    print(dic)
    d = 4
f = 5
func() ## 只打印 f
g = 6

3 .利用globals批量建立全域性變數

globals實現,通過字串建立一個全域性變數

globals返回的是系統內建的一個字典

通過往內建字典中新增鍵值對,實現全域性變數的建立

dic = globals()
# 通過往內建字典中新增鍵值對,實現全域性變數的建立
dic["wangwen"] = "王文"
print(dic)
print(wangwen) #"王文"

四、迭代器

迭代器:能被next()函式呼叫並不斷返回下一個值的物件稱為迭代器(Iterator 迭代器是物件)

概念:迭代器指的是迭代取值的工具,迭代是一個重複的過程,每次重複都是基於上一次的

結果而繼續的,單純的重複並不是迭代

特徵:並不依賴索引,而通過next指標(記憶體地址定址)迭代所有資料,一次只取一個值,

而不是一股腦的把所有資料放進記憶體.大大節省空間

1、 可迭代性物件

如果一個物件中含有__iter__這個成員,說明該資料是可迭代性物件;

ps:檢視該物件中的成員,dir

setvar = {"白金鴿","楊特","郝建康"}
# 檢視該物件中的成員,dir
lst = dir(setvar)
if '__iter__' in lst:
    print("該資料是可迭代性資料")
print(lst)

2、 迭代器

如果是迭代器,一定是可迭代物件
如果是可迭代物件,不一定是迭代器;

1.如何變成一個迭代器

setvar = {"白金鴿","楊特","郝建康"}
# 1.如何變成一個迭代器
it = iter(setvar) # 方法一
it = setvar.__iter__() # 方法二
lst = dir(it) 
print(lst)

2.如何判斷一個迭代器 __iter__ + __next__

if "__iter__" in lst and "__next__" in lst:
    print("該資料是迭代器")

3.如何呼叫一個迭代器

 1 # 方法一
 2 res = next(it)
 3 print(res)
 4 res = next(it)
 5 print(res)
 6 res = next(it)
 7 print(res)
 8 # res = next(it) error
 9 # print(res)
10 
11 # 4.重置迭代器
12 it = iter(setvar)
13 # res = next(it)
14 res = it.__next__()
15 print(res)
16 
17 # 方法二
18 print("<=========>")
19 for i in it:
20     print(i)
21 # next(it) error 單項不可逆的過程
22 
23 # 方法三
24 print("<=========>")
25 setvar = {"白金鴿","楊特","郝建康","於盛林","楊業","王娟娟","草配線","孟凡偉"}
26 it = iter(setvar)  # setvar.__iter__()
27 for i in range(8):
28     print(next(it))
View Code

五、高階函式

高階函式 : 能夠把函式當成引數傳遞的就是高階函式

1、map(func,Iterable) : 處理資料

功能:
  把Iterable中的資料一個一個的傳遞到func函式當中進行處理,處理之後的結果通過迭代器一個一個獲取
引數:
  func:內建或者自定義函式
  Iterable : 可迭代性資料(容器型別資料 range物件 迭代器)
返回值:
  迭代器

# (1) ["1","2","3","4"]  => [1,2,3,4]
lst = ["1","2","3","4"]
lst_new = []
for i in lst:
    # print(int(i))
    lst_new.append(int(i))
print(lst_new)


# 使用map改寫
it = map(int,lst)
for i in it:
    print(i,type(i))
print(list(it))
# (2) [1,2,3,4] => [5,10,15,20]
lst = [1,2,3,4]
lst_new = []
for i in lst:
    res = i * 5
    lst_new.append(res)
print(lst_new)

# 使用map改寫
""" 注意點  : 引數和返回值必不可少"""
def func(n):
    print(1111111111)
    return n * 5
it = map(func,lst)

2、reduce(func,Iterable) 計算資料

功能:
先把Iterable中的前兩個資料拿出來,扔到func中做處理,得出一個結果,
在拿當前結果和Iterable的下一個值在繼續扔到func做計算,
依次類推...
直到最後返回結果.
引數:
  func : 自定義函式
  Iterable : 可迭代性物件(容器型別資料 , range物件 , 迭代器)
返回值:
  計算最後的結果

#(1) [5,4,8,8] => 5488
from functools import reduce

def func(x,y):
    return x*10 + y
lst = [5,4,8,8]
res = reduce(func,lst)
print(res,type(res))

# lambda 改造
print(reduce(  lambda x,y : x*10 + y  , lst))
# (2) "5488" => 5488 不讓使用int函式
def func(x,y):
    return x*10 + y

def func2(n):
    dic = {}
    for i in range(10):
        dic[str(i)] = i
    return dic[n]
    
# 功能: "5488" => 5,4,8,8
it = map(func2,"5488")
# 功能: [5,4,8,8] => 5488
res = reduce(func,it)
print(res , type(res))

3、filter(func,Iterable)過濾資料

功能:
  通過自定函式的返回值控制當前資料保留與否
  return True 代表保留
  return False 代表捨棄
引數:
  func : 自定義的函式
  Iterable : 可迭代性資料(容器型別資料,range物件,迭代器)
返回值:
  迭代器

# lst = [1,12,435,234,122,2]  => 過濾掉偶數,保留奇數
lst = [1,12,435,234,122,2] 
lst_new = []
for i in lst:
    if i % 2 == 1:
        lst_new.append(i)
print(lst_new)

# 使用filter進行改造
def func(n):
    if n % 2 == 1:
        return True
    else:
        return False

it = filter(func,lst)
lst = list(it)
print(lst)

# 使用lambda 進行改造
print(list(filter( lambda n : True if n % 2 == 1 else False , lst )))

4、sorted(Iterable , reverse=False , key = 函式)

功能:
  排序資料
引數:
  Iterable : 可迭代物件 (容器型別資料 range物件 迭代器)
  reverse : 正序或者倒序 reverse = False (從小到大)
  key : 內建或者自定義方法
返回值:
  排序後的資料(列表)

# 1.從小到大
lst = [-9,18,13,16,99,87]
res = sorted(lst)
print(res)

# 2.從大到小
res = sorted(lst,reverse=True)
print(res)

sort 和 sorted的區別:
  [sorted] 推薦
    1.sorted 可以對所有的容器型別資料排序
    2.返回一個新的列表
  [sort]
    1.sort 只能對列表這一個型別進行排序
    2.針對於原有的列表進行排序

六 、推導式

概念: 通過一行迴圈判斷,遍歷出一系列資料的方法就是推導式

推導式種類三種:
  [val for val in Iterable] 列表推導式
  {val for val in Iterable} 集合推導式
  {a:b for a,b in iterable} 字典推導式

1.列表推導式

1.單迴圈推導式基本語法

# 建立列表,內容為1~50
lst = [ i for i in range(1,51) ]
print(lst)

2.帶有判斷條件的單迴圈推導式

注意點: 在迴圈後面只能跟單項分支

# 1 ~ 100 中的所有偶數保留到列表裡
lst = []
for i in range(1,101):
    if i % 2 == 0 :
        lst.append(i)
print(lst)

# 改寫推導式
lst = [ i for i in range(1,101) if i % 2 == 0  ]
print(lst

3.多迴圈推導式基本語法

lst1 = ["於盛林","荷葉","王永娟"]
lst2 = ["李琦","朱培峰","劉靈鎮"]

lst = []
for i in lst1:
    for j in lst2:
        lst.append(i + "" + j)
print(lst)

# 改寫推導式
lst = [ i + "" + j for i in lst1 for j in lst2 ]
print(lst)

4.帶有判斷條件的多迴圈推導式

lst = []
for i in lst1:
    for j in lst2:
        if lst1.index(i) == lst2.index(j):
            lst.append(i + "" + j)
print(lst
# 改寫推導式
lst = [ i + "" + j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j) ]
print(lst)

2.集合推導式

"""
案例:
    滿足年齡在18到21,存款大於等於5000 小於等於5500的人,
    開卡格式為:尊貴VIP卡老x(姓氏),否則開卡格式為:摳腳大漢卡老x(姓氏)    
    把開卡的種類統計出來
"""
data = [
    {"name":"李琦","age":22,"money":20000},
    {"name":"李雅琪","age":19,"money":12000},
    {"name":"吳洪昌","age":18,"money":5300},
    {"name":"王召","age":80,"money":4000},
    {"name":"王生父","age":81,"money":5400}
]

setvar = set()
for i in data:
    if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500:
        strvar = "尊貴VIP卡老{}".format(i["name"][0])
    else:
        strvar = "摳腳大漢卡老{}".format(i["name"][0])
    # 把對應的開卡格式存入到集合當中
    setvar.add(strvar)
print(setvar)

# 改寫成集合推導式
# 三運運算子  + for迴圈 => 集合推導式
setvar = { "尊貴VIP卡老{}".format(i["name"][0]) if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500 else "摳腳大漢卡老{}".format(i["name"][0])  for i in data }    
print(setvar)    
View Code

3.字典推導式

(1)enumerate

enumerate(iterable,[start=0])
功能:  列舉 ; 將索引號和iterable中的值,一個一個拿出來配對組成元組,通過迭代器返回
引數:
   iterable: 可迭代性資料 (常用:迭代器,容器型別資料,可迭代物件range)
   start: 可以選擇開始的索引號(預設從0開始索引)
返回值: 迭代器

lst = ["歡慶","尤佳","劉文波","黃長劍"]
it = enumerate(lst)  # 預設從0開始索引
it = enumerate(lst,start=1) # start = 1表示從1開始列舉配對;
# 1.配合enumerate完成字典推導式操作
dic = { k:v for k,v in enumerate(lst) }
print(dic)
# 2.直接通過dict強轉
dic = dict(enumerate(lst))
print(dic)

(2)zip(iterable, ... ...)

功能: 將多個iterable中的值,一個一個拿出來配對組成元組,通過迭代器返回
  iterable: 可迭代性資料 (常用:迭代器,容器型別資料,可迭代物件range)
返回: 迭代器
原則: zip的配對原則會按照相同的索引組合,如果沒有相同的索引自動捨棄;

# 1.配合zip完成字典推導式操作
lst_key = ["zy","sxy","jyh"]
lst_val= ["張印","孫翔宇","家營和"]
dic = { k:v for k,v in zip(lst_key,lst_val) }
print(dic)

# 2.直接通過dict強轉
dic = dict(zip(lst_key,lst_val))
print(dic)

七、生成器

生成器本質是迭代器,允許自定義邏輯的迭代器

迭代器和生成器區別:
  迭代器本身是系統內建的.重寫不了.而生成器是使用者自定義的,可以重寫迭代邏輯

生成器可以用兩種方式建立:
  (1)生成器表示式 (裡面是推導式,外面用圓括號)
  (2)生成器函式 (用def定義,裡面含有yield)

1、生成器表示式

# 生成器表示式
gen = (i for i in range(100))
print(gen) # generator

# 呼叫生成器
# 1.next
res = next(gen)
print(res)

# 2.for + next (推薦)
for i in range(3):
    print(next(gen))
    
# 3.for  (慎用,防止資料量較大時,形成類似於死迴圈的效果)
# for i in gen:
    # print(i)

# 4.list (慎用,防止資料量較大時,記憶體溢位,出現藍屏)
lst = list(gen)
print(lst)

2、生成器函式

yield 類似於 return
共同點在於:執行到這句話都會把值返回出去
不同點在於:yield每次返回時,會記住上次離開時執行的位置 , 下次在呼叫生成器 , 會從上次執行的位置往下走
      而return直接終止函式,每次重頭呼叫.

1.生成器函式語法

def mygen():
    print("one")
    yield 1
    
    print("two")
    yield 2
    
    print("three")
    yield 3
    
# 初始化生成器函式 => 返回生成器物件 , 簡稱生成器
gen = mygen()
res = next(gen)

2.生成器優化寫法

def mygen():
    for i in range(1,101):
        yield "新制造的籃球球衣號碼是{}".format(i)
        
# 初始化生成器函式 => 返回生成器物件 , 簡稱生成器
gen = mygen()

# 先獲取前30個數據
for i in range(30):
    print(next(gen))

3.send語法的使用

send send傳送值的時候,是給上一個yield

next和send區別:
  next 只能取值
  send 不但能取值,還能傳送值
send注意點:
  第一個 send 不能給 yield 傳值 預設只能寫None
  最後一個yield 接受不到send的傳送值

 1 def mygen():
 2     print("start ... ")
 3     res = yield "111"
 4     print(res)
 5     
 6     res = yield "222"
 7     print(res)
 8     
 9     res = yield "333"
10     print(res)
11     
12     res = yield "444"
13     print(res)
14     print("end ... ")
15     
16 # 初始化生成器函式 => 返回生成器物件 , 簡稱生成器
17 gen = mygen()
18 # 第一次傳送資料時,無腦加None
19 res = gen.send(None)
20 print(res)
21 res = gen.send("我來了老妹2")
22 print(res)
23 res = gen.send("我來了老妹3")
24 print(res)
25 res = gen.send("我來了老妹4")
26 print(res)
27 # res = gen.send("我來了老妹5") error
28 # print(res)
View Code

4. yield from 的基本使用

yield from : 將一個可迭代物件變成一個迭代器返回

def mygen():
    # yield [1,2,3,4,5]
    yield from [1,2,3,4,5]
gen = mygen()
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))