1. 程式人生 > >day 06 列表去重, 資料型別的補充,編碼,深淺copy

day 06 列表去重, 資料型別的補充,編碼,深淺copy

因為重要,所以放前面

列表去重

l1 = [1, 2, 3, 4, 5]
l2 = [3, 4, 5, 6, 7]
set = list(set(l1 + l2))      # set自動去重,然後變成list型別
print(set)     #  [1, 2, 3, 4, 5, 6, 7]

1、 id    is    ==

== 是比較的兩邊的數值是否相等,而 is 是比較的兩邊的記憶體地址是否相等。 如果記憶體地址相等,那麼這兩邊其實是指向同一個記憶體地址。

l1 = [1, 2, 3]
l2 = [1, 2, 3]
print(l1, l2) print(id(l1), id(l2)) # 值相同,ID不同
l1 = [1, 2, 3]
l2 = [1, 2, 3]
print(l1 == l2)  # True
print(l1 is l2)  # False

可以說如果記憶體地址相同,那麼值肯定相同,但是如果值相同,記憶體地址不一定相同。

程式碼塊:   瞭解

Python程式是由程式碼塊構造的。塊是一個python程式的文字,他是作為一個單元執行的。

程式碼塊:一個模組,一個函式,一個類,一個檔案等都是一個程式碼塊。

而作為互動方式輸入的每個命令都是一個程式碼塊。

對於一個檔案中的兩個函式,也分別是不同的程式碼塊

程式碼塊的快取機制  瞭解 

程式碼塊的快取機制的適用範圍: int(float),str,bool

int(float):任何數字在同一程式碼塊下都會複用。

bool:True和False在字典中會以1,0方式存在,並且複用。

str:幾乎所有的字串都會符合快取機制

小資料池:  提升效率,節約記憶體

Python自動將-5~256的整數進行了快取,當你將這些整數賦值給變數時,並不會重新建立物件,而是使用已經建立好的快取物件。

python會將一定規則的字串在字串駐留池中,建立一份,當你將這些字串賦值給變數時,並不會重新建立物件, 而是使用在字串駐留池中建立好的物件。

其實,無論是快取還是字串駐留池,都是python做的一個優化,就是將~5-256的整數,和一定規則的字串,放在一個‘池’(容器,或者字典)中,無論程式中那些變數指向這些範圍內的整數或者字串,那麼他直接在這個‘池’中引用,言外之意,就是記憶體中之建立一個。

優點:能夠提高一些字串,整數處理人物在時間和空間上的效能;需要值相同的字串,整數的時候,直接從‘池’裡拿來用,避免頻繁的建立和銷燬,提升效率,節約記憶體。

總結:

  如果在同一程式碼塊下,則採用同一程式碼塊下的換快取機制。

  如果是不同程式碼塊,則採用小資料池的駐留機制

# pycharm 通過執行檔案的方式執行下列程式碼:  這是在同一個檔案下也就是同一程式碼塊下,採用同一程式碼塊下的快取機制。
i1 = 1000
i2 = 1000
print(i1 is i2)  # 結果為True 因為程式碼塊下的快取機制適用於所有數字
通過互動方式中執行下面程式碼:   # 這是不同程式碼塊下,則採用小資料池的駐留機制。
>>> i1 = 1000
>>> i2 = 1000
>>> print(i1 is i2)
False  # 不同程式碼塊下的小資料池駐留機制 數字的範圍只是-5~256.
# 雖然在同一個檔案中,但是函式本身就是程式碼塊,所以這是在兩個不同的程式碼塊下,不滿足小資料池(駐存機制),則指向兩個不同的地址。
def func():
    i1 = 1000
    print(id(i1))  # 2288555806672

def func2():
    i1 = 1000
    print(id(i1))  # 2288557317392

func()
func2()

 

2、資料型別補充: int, str, bool,list,tuple,dict,set。

# 資料型別之間的轉換:
# str ---> list split

# list ---> str join

# bool :False 0 '' [] () {} set()

list <----> tuple

# list <--->  tuple
l1 = [1,2,3]
tu1 = tuple(l1)
l2 = list(tu1)
print(tu1)
print(l2)

list <------ dict

# list <---- dict
dic1 = {'name': 'alex', 'age': 12}
print(list(dic1))

list <------dict

# list <---- dict
dic1 = {'name': 'alex', 'age': 12}
print(list(dic1))

list <------>  set

# list <---> set ***
li = [1, 2, 3, 4, 5]
set = set(li)
print(set, type(set))
set = {1, 2, 3, 4, 5}
list = list(set)
print(list)

元組補充: 

元組中只有一個元素並且沒有逗號,則他不是元組,與元素資料型別相同。
tu1 = (1)
tu2 = (1)
print(tu1, id(tu1), type(tu1))  # 1 1558496944 <class 'int'>
print(tu2, id(tu2), type(tu2))  # 1 1558496944 <class 'int'>
tu1 = (1,)
tu2 = (1,)
print(tu1, id(tu1), type(tu1))  # (1,) 2880293370120 <class 'tuple'>
print(tu2, id(tu2), type(tu2))  # (1,) 2880294252048 <class 'tuple'>

 

踩坑題

坑1:li = [11, 22, 33, 'alex', 55]  將列表中索引為奇數位的元素刪除

錯誤事例:  

li = [11, 22, 33, 'alex', 55]
for index in range(len(li)):
    if index % 2 == 1:
        li.pop(index)
print(li)                    #  [11, 33, 'alex']   刪除的是索引為1,4 的元素

# 原因:pop在刪除索引1後,會將後面元素,全部向前提一位 (補空)
#  解決方法: 迴圈從後面開始

解決方法:

一,從後面開始迴圈

li = [11, 22, 33, 'alex', 55]
for index in range(len(li)-1, -1, -1):
    if index % 2 == 1:
        li.pop(index)
print(li)

二,建立新列表,將偶數選出,然後覆蓋 li 列表

li = [11, 22, 33, 'alex', 55]
l1 = []
for index in range(len(li)):
    if index % 2 == 0:
        l1.append(li[index])
li = l1
print(li)
總結:在迴圈一個列表時,最好不要改變列表的大小,這樣會影響你的最終結果

坑二:
 dic = {'k1':1,'k2':2, 'k3': 3, 'name': '太白'}
將字典中鍵含有k元素的鍵值對刪除
錯誤示例:
dic = {'k1':1,'k2':2, 'k3': 3, 'name': '太白'}
for key in dic:
    if 'k' in key:
        dic.pop(key)
l1 = []
# 結果報錯 dictionary changed size during iteration

解決方法:

dic = {'k1': 1, 'k2': 2, 'k3': 3, 'name': '太白'}
l1 = []
for key in dic:
    if 'k' in key:
        l1.append(key)
for k1 in l1:
    dic.pop(k1)
print(dic)

總結:dict 在迴圈一個字典時,不能改變字典的大小,會報錯


編碼的進階:
 ascii,unico,utp-8,gbk四個編碼本:
1,不同的編碼之間能否互相識別(報錯或者出現亂碼)。 不能!!
2, 規定:文字通過網路傳輸,或者硬碟儲存不能使用Unicode編碼方式。 耗記憶體

大前提:
python3x環境:
唯獨str型別:他在內部編碼方式是unicode
所以 python3x中的字串不能用於直接的網路傳輸 檔案的儲存 '中午請我去吃飯'

補充一個數據型別:bytes型別 與str型別是海爾兄弟。
為啥要有bytes:
bytes內部編碼方式非unicode

為啥還要有str? bytes直接就解決了所有問題呀?
bytes 中文是16進製表示,看不懂。
英文:
str:
表現形式:'alex'
內部編碼:unicode

bytes:
表現形式:b'alex'
內部編碼:非unicode

中文:
str:
表現形式:'屌絲'
內部編碼:unicode

bytes:
表現形式:b'\xe5\xb1\x8c\xe4\xb8\x9d''
內部編碼:非unicode

bytes:當你需要網路傳輸資料,檔案儲存資料時要考慮到bytes。

str ---> bytes(gbk utf-8)
unicode ---> gbk utf-8

bype 用法:
s1 = 'alex'
b1 = b'alex'
print(b1,type(b1))    # b'alex' <class 'bytes'>
print(b1.upper())   # b'ALEX'
 

編碼之間的轉換

# unicode ---> gbk 字串 ---> gbk編碼方式的bytes
s1 = '太白'
b1 = s1.encode('gbk') # 編碼
s2 = b1.decode('gbk') # 解碼
print(s2)
# unicode ---> utf-8  字串 ---> utf-8 編碼方式的bytes
s2 = '太白'
b2 = s2.encode('utf-8')
s3 = b2.decode('utf-8')
print(s3)
# gbk ---> utf-8
#
b1 = b'\xcc\xab\xb0\xd7'  # gbk編碼的bytes型別
s = b1.decode('gbk')
b2 = s.encode('utf-8')  # utf-8編碼的bytes型別
print(b2)

 

深淺copy

淺copy,在記憶體中建立一個新的list(dict),但是新的列表裡面的元素還是與原列表共用一個

# 淺copy
# 在記憶體中建立一個新的list(dict),但是新的列表裡面的元素還是與原列表共用一個。
l1 = [1, 'alex', [11, 22]]
l2 = l1.copy()
print(id(l1), id(l2))     #  1893402849992 1893402850760
l1.append(33)
print(l1, l2)             # [1, 'alex', [11, 22], 33] [1, 'alex', [11, 22]]
print(id(l1[0]))          # 1558496944
print(id(l2[0]))          # 1558496944
print(id(l1[-1]))         # 1558497968
print(id(l2[-1]))         # 1893402827784
print(l1 is l2)           # print(l1 is l2)  

深COPY

深copy會在記憶體中對原列表(dict)以及列表裡面的可變的資料型別重新建立一份,而列表中不可變的資料型別還是沿用原來的

import copy
l1 = [1, 'alex', [11,22]]
l2 = copy.deepcopy(l1)
# l1[0] = 1000
print(l1)
print(l2)
# print(id(l1))
print(id(l2))
print(id(l1[-1]))  # 2190627337480
print(id(l2[-1]))  # 2190627338888
print(id(l1[0]))
print(id(l2[0]))
l1[-1].append(666)
print(l1)
print(l2)