Python基礎 - 序列結構


有序序列:

  • 列表、元組、字符串

無序序列:

  • 字典、集合

可變序列:

  • 列表、字典、集合

不可變序列:

  • 元組、字符串

基本涉及功能:

  • 增、刪、查、改

列表:升級版數組

特點:

  • 支持雙向索引
  • 包含若干元素的有序連續內存空間,數據增刪改時,自動進行內存的擴展或收縮
  • 盡量從列表尾部進行元素的追加、刪除操作
  • Python基於值的自動內存管理變量存儲的是值的內存地址,列表元素也是值的引用,所以列表可以存不同類型的數據
  • 列表能增刪查改,但同時負擔也很重,需根據實際情況選擇合適的數據類型,要盡量避免過多使用列表

列表的創建與刪除

a_list = [1,3,'abc', 'xyc']
a_list = []  # 創建空列表
list((1,3,5,7,9))
[1, 3, 5, 7, 9]
list(range(1,11,2)) # 將range對象轉為列表
[1, 3, 5, 7, 9]
list("hello world")  # 將字符串轉為列表
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
list({1,3,4,4,5,6,'b'})  # 將集合轉為列表
[1, 3, 4, 5, 6, 'b']
list({'a':3, 'b':4, 'c':5})  # 將字典的key轉為列表
['a', 'b', 'c']
list({'a':3, 'b':4, 'c':5}.values())  # 將字典的value轉為列表
[3, 4, 5]
list({'a':3, 'b':4, 'c':5}.items())  # 將字典的key-value轉為列表 
[('a', 3), ('b', 4), ('c', 5)]
x = list()  # 創建空列表
x = [1,2,3]
del x  # 刪除列表對象
x 
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-14-bcecaca5435f> in <module>()
      1 x = [1,2,3]
      2 del x  # 刪除列表對象
----> 3 x


NameError: name 'x' is not defined

列表元素訪問

x = list("Python")
x
['P', 'y', 't', 'h', 'o', 'n']
x[0]
'P'
x[-1]
'n'
x[2] # 第3個元素
't'
x[1:3]  # 切片,前閉后開,1,2號元素
['P', 'y']
x[-4:-6:-1] # 右邊索引,步長要為負數
['t', 'y']

列表常用方法(增刪查改)


l.apped(x)
l.insert(index, x)
l.extend(L)
刪:
l.remove(x)
l.pop(index) 刪除並返回該元素,默認是尾部
l.clear()
del l[index]
** 查**:
l[index]
改:
l[index] = value

append(); insert(); extend()

x = [1,2,3]
id(x)  # 查看對象的內存地址
642846558152
x.append(4)  # 尾部追加
print(x)
id(x)  # 不改變列表內存地址(是同一個對象)
[1, 2, 3, 4]





642846558152
x.insert(3, 'aaa')  # 前插,后挪, 消耗大,慎用
x
[1, 2, 3, 'aaa', 4]
x.extend(['bb','cc','dd'])  # 尾部追加多個元素
x
[1, 2, 3, 'aaa', 4, 'bb', 'cc', 'dd']

pop(); remove(); clear()

x = [1,2,3,4,5,6,7]
x.pop()  # 刪除,並彈出尾部元素
7
x.pop(0)
1
x
[2, 3, 4, 5, 6]
x.clear()  # 清空所有元素
x
[]
x = [1,2,2,3,4]
x.remove(2)  # 刪除首個值為2的元素
x
[1, 2, 3, 4]
del x[3]  # 刪除指定索引的元素
x 
[1, 2, 3]

注意: 列表具有內存自動收縮、擴張功能,不適合在中間位置進行元素的增刪,而且會改變后面所有元素索引值

查、改

list[index] = value; l.index(value)

x = [1,2,3,4]
x.index(3)  # 返回值首次出現值為3 的index
2
x[2] = 'abc'  # 將列表里值為 3 的元素替換為 abc:  1、找到3的索引: list.index(3); 2: list[index] = value
x
[1, 2, 'abc', 4]

count(); index()

x = [1,2,3,3,6,6,5,6,6,4,'aaa']
x.count(6)  # 元素 3 在列表中出現的次數
4
x.count(3)
2
x.count('a')
0
x.index(3)  # 元素2 在列表中首次出現的index
2
x.index('dfsf')  # 沒找到則拋出異常
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-65-b1f8470b4d3d> in <module>()
----> 1 x.index('dfsf')  # 沒找到則拋出異常


ValueError: 'dfsf' is not in list

提示:列表會在很多地方拋出異常,從而導致程序的崩潰,解決方法有種:

  • 選擇結構if-else過濾掉可能會異常的情況
  • 異常處理try - except - else處理異常情況
import random
random.sample([1,3,4,2,4,5,6,4,3,2,],7)
[4, 1, 3, 6, 2, 3, 2]

Signature: random.sample(population, k)
Docstring:
Chooses k unique random elements from a population sequence or set.

Returns a new list containing elements from the population while
leaving the original population unchanged. The resulting list is
in selection order so that all sub-slices will also be valid random
samples. This allows raffle winners (the sample) to be partitioned
into grand prize and second place winners (the subslices).

Members of the population need not be hashable or unique. If the
population contains repeats, then each occurrence is a possible
selection in the sample.

To choose a sample in a range of integers, use range as an argument.
This is especially fast and space efficient for sampling from a
large population: sample(range(10000000), 60)
File: d:\software\anaconda3\lib\random.py
Type: method

assert 1 < 2, print("斷言錯啦")   # 斷言正確則會忽略后面的表達式
assert 9 < 5, print("斷言錯啦")  # assert 失敗則會返回后面表達式的值, 有點像 if-else
斷言錯啦



---------------------------------------------------------------------------

AssertionError                            Traceback (most recent call last)

<ipython-input-77-4b61c3dd7e47> in <module>()
----> 1 assert 9 < 5, print("斷言錯啦")  # assert 失敗則會返回后面表達式的值, 有點像 if-else


AssertionError: None
lst = random.sample(range(100, 1000), 100)  # 從100-999里選出100個數字,組成列表

while True:
    x = input("請輸入一個3位數:")
    try:
        assert len(x) == 3, "長度必須為3"     # assert exp1 exp2  斷言,exp1,如果斷言失敗False,提示exp2
        x = int(x)
        break
    except:
         print("好像有些不對哦")
    
if x in lst:
    print("元素{0}在列表中的索引為:{1}".format(x, lst.index(x)))  # str.format() 和 占位符%s, %d,沒啥區別呀
else:
    print("列表中不存在該元素")
   
請輸入一個3位數:1234
好像有些不對哦
請輸入一個3位數:666
列表中不存在該元素

sort(); reserve()

Docstring: L.sort(key=None, reverse=False) -> None -- stable sort IN PLACE

x = list(range(11))
import random
random.shuffle(x)  # 將列表元素隨機亂序
x
[6, 4, 8, 0, 3, 1, 7, 10, 9, 5, 2]
x.sort(key=lambda s: len(str(s)), reverse=True)  # 轉成字符串,按字符串長度降序排列
x
[10, 6, 4, 8, 0, 3, 1, 7, 9, 5, 2]
x.sort(key=str)  # 轉成字符串,按大小升序排列
x
[0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]
x.sort() # 按默認規則排序(升序)
x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
x.reverse()  # 元素逆序
x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

注意:列表的L.sort(key=None, reverse=False); L.reverse()是原地排序會改變元素的位置;而內置的sorte(key=None, reverse=False); reversed()則張返回新的列表對象

from operator import itemgetter

Init signature: itemgetter(self, /, *args, **kwargs)
Docstring:
itemgetter(item, ...) --> itemgetter object

Return a callable object that fetches the given item(s) from its operand.
After f = itemgetter(2), the call f(r) returns r[2].
After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])

game_result = [['Bob', 95.0, 'A'],
               ['Alan', 86.0, 'C'],
               ['Mandy', 83.5, 'A'],
               ['Rob', 89.3, 'E']
    
]
sorted(game_result, key=itemgetter(2))  # 按子列表第三個元素"A,C,E"進行排序
[['Bob', 95.0, 'A'],
 ['Mandy', 83.5, 'A'],
 ['Alan', 86.0, 'C'],
 ['Rob', 89.3, 'E']]
sorted(game_result, key=itemgetter(2,0))  # 先按第3個元素,再按第一個元素排序
[['Bob', 95.0, 'A'],
 ['Mandy', 83.5, 'A'],
 ['Alan', 86.0, 'C'],
 ['Rob', 89.3, 'E']]

還有還多的玩法,這里就暫時不去列舉了

列表對象支持運算符

x = [1,2,3]
id(x)
642845987464
x = x +[4] # + 不屬於原地操作,而是返回新列表,且涉及大量元素賦值,效率非常低
id(x)
642846834248
x += [5]  # += 屬於原地操作,與append()方法一樣高效
id(x)
642846834248
x = [1,2,3]
id(x)
642858941128
x = x*2  # 元素重復,返回新列表
print(x)
print(id(x))
[1, 2, 3, 1, 2, 3]
642847377608
x *= 2  # *= 的方式,地址不變,效率很高
3 
print(x)
print(id(x))
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
642847377608
[1,2,3,3,4] * 0  # 重復0次,清空,等同於 l.clear() 或 [:] = []
[]
3 in [1,2,4]  # 成員測試
False

內置函數對列表的操作

max(); min(); sum(); len();zip();map();reduce();filter();enumberate();all()....

x = list(range(11))
import random

random.shuffle(x)
x
[3, 1, 0, 9, 4, 10, 5, 8, 7, 6, 2]
all(x)  # 是否所有元素都等價於True
False
any(x) # 是否存在等價於True的元素
True
max(x)
10
max(x,key=str) # 轉成字符串最大
9
list(zip(x, [1] * 20))  # 多列表元素重組
[(3, 1),
 (1, 1),
 (0, 1),
 (9, 1),
 (4, 1),
 (10, 1),
 (5, 1),
 (8, 1),
 (7, 1),
 (6, 1),
 (2, 1)]
list(zip(['a','b','c'],[1,2]))
[('a', 1), ('b', 2)]
x
[3, 1, 0, 9, 4, 10, 5, 8, 7, 6, 2]
dict(enumerate(x))  # 組合成列表
{0: 3, 1: 1, 2: 0, 3: 9, 4: 4, 5: 10, 6: 5, 7: 8, 8: 7, 9: 6, 10: 2}

列表推導式

語法:
[ expression for i in sequence if condition1
​ for j in sequence if condition2
​ for k in sequenxe if condition3
​ ........
​ for n in sequence if conditionn]

阿凡提要米問題,共64格,第一,1粒;第二,2粒;第三4粒;第四8粒....一共64格子,需要多少米

rice = sum([2 ** i for i in range(1,65)])
# 按照一斤26000粒算
total = rice / (2600 * 2 * 1000)  # 用噸 來計量
print(total)
7094901566811.366

實現嵌套列表的平鋪

vec = [[1,2,3], [4,5,6], [7,8,9]]

[num for elem in vec for num in elem]  # 先遍歷列表元素,每個元素又是個列表,再遍歷每個列表,返回元素
[1, 2, 3, 4, 5, 6, 7, 8, 9]

多級嵌套還可以用遞歸實現

def flat_list(lst):
    result = []  # 存放最終結果的列表
    def nested(lst):  # 函數內部嵌套函數,功能:遍歷元素,直到不能夠遍歷為止
        for i in lst:
            if isinstance(i, list):
                nested(i)  # 遞歸子列表
            else:
                result.append(i)
    nested(lst)
    return result

flat_list([4,5,6,[7,8,9,[11,12,13,[13,14,15,[16,17,[18,19,[20,[21]]]]]]]])

[4, 5, 6, 7, 8, 9, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21]

過濾不符合條件元素

# 列出當前文件夾下所有Python源文件 
import os
[filename for filename in os.listdir('.') if filename.endswith(('.py', '.pyw'))]
[]
a_list = [-1, -4, 6, 7.5, -2, 3, 9, -11]
[i for i in a_list if i > 0]  # 所有大於0的數字  組成新列表
[6, 7.5, 3, 9]
# 給定一個成績字典,要求計算score的最高分、最低分、平均分、最高分的同學是誰
scores = {'zs': 45,
          'lisi': 78,
          'wang wu': 40,
          'zhao liu': 96,
          'zhao qi': 65,
          'sun ba': 90,
          'zj': 78,
          "chen jie":99
                         }
# 本質還是考字典操作,鍵、值的操作嘛,以后可能會更復雜在變量很多,嵌套很多,其實原理是一樣的

high_est = max(scores.values())

low_est = min(scores.values())

average = sum(scores.values()) / len(scores)

print(high_est, low_est, average)  # 同時輸出最高、最低、平均分

# 尋找最高分的key  其實就是調用 ditc.items() 
highest_person = [name for name, score in scores.items() if score == high_est]

print(highest_person)


99 40 73.875
['chen jie']
# 查找列表中最大元素的所有位置

import random

x = [random.randint(10, 20) for _ in range(20)]  # 先寫for循環(只表示循環次數,下划線,降低閱讀干擾),最后再寫 每次 要執行的 表達式

max_num = max(x) # 找出最大值

[index for index, value in enumerate(x) if value == max_num]

[1, 7, 15]

同時遍歷多個可迭代對象

[(x,y) for x in [1,2,3] for y in [1,3,4] if x != y]
[(1, 3), (1, 4), (2, 1), (2, 3), (2, 4), (3, 1), (3, 4)]
[(x,y) for x in [1,2,3] if x == 1 for y in [3,1,4] if x != y]
[(1, 3), (1, 4)]

切片

索引更強大的一點在於,切片不會因為下標越界而拋出異常,代碼具有更強的健壯性,注意切片是生成了新的對象

a_list = [3,4,5,6,7,9,11,13,15,17]

print(id(a_list))
1043253510920
a_list[:]  # 此時已經生成了新的列表

print(id(a_list))
1043253511880
a_list = a_list[::-1]  # 逆序,跟l.reverse()不同在於,切片是產生新的對象,而reverse()方法是原地逆序,指針不變

print(id(a_list))
1043253511880
a_list
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]

s = "張三,98"
type(s)
str
a = eval(s)
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-17-e6943141c006> in <module>()
----> 1 a = eval(s)


<string> in <module>()


NameError: name '張三' is not defined
a_list[::2]
[3, 5, 7, 11, 15]
a_list[1::2]
[4, 6, 9, 13, 17]
a_list
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
a_list[3:6]  # 前閉后開
[6, 7, 9]
a_list[:10000]  # 自動尾部截斷,不會報錯
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
a_list[100:]
[]
a_list[100]  # 不能越界訪問
---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

<ipython-input-27-b5f68ab1fd00> in <module>()
----> 1 a_list[100]  # 不能越界訪問


IndexError: list index out of range

切片- 增加元素

屬於原地操作,不改變列表的地址

lst = [3,5,7]
id(lst)
1043253645832
lst[len(lst):]
[]
# 在尾部增加元素, 地址不變

lst[len(lst): ] = [9]

id(lst)
1043253645832
lst[: 0] = [1,2]  # 頭部增加元素
print(lst)
print(id(lst))
[1, 2, 1, 2, 1, 2, 1, 2, 3, 5, 7, 9]
1043253645832
lst[1:1] = ['cj'] # 在第2個元素,前插1 
lst
[1, 'cj', 'c', 'j', 'c', 'j', 2, 1, 2, 1, 2, 1, 2, 3, 5, 7, 9]
lst[3:3] = [6,6] # 在中間位置插入多個元素
lst
[1,
 'cj',
 'c',
 6,
 6,
 6,
 6,
 6,
 6,
 6,
 6,
 6,
 6,
 6,
 6,
 'j',
 'c',
 'j',
 2,
 1,
 2,
 1,
 2,
 1,
 2,
 3,
 5,
 7,
 9]

切片- 刪除元素

lst = [3,5,7,9]
lst[:3] = []
lst
[9]
lst = [3,5,7,9]
del lst[:2]
lst
[7, 9]

切片- 查、改元素

lst = [1,3,5,7]
lst[:1] = [6,6]
lst
[6, 6, 6, 3, 5, 7]
lst[::2] = zip('abc', range(4))
lst
[('a', 0), 6, ('b', 1), 3, ('c', 2), 7]

元組:輕量級列表

x = (1,2,4)
type(x)
tuple
x[-1]
4
x[-1] = 666  # 支持索引查看,不能修改元素
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-58-8646078b016b> in <module>()
----> 1 x[-1] = 666  # 支持索引查看,不能修改元素


TypeError: 'tuple' object does not support item assignment
x = ()  # 空元組,等價於 x = tuple()
x = (3,)  # 只有一個元素時,要增加一個逗號
tuple(range(5))
(0, 1, 2, 3, 4)
list(enumerate(range(5)))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
list(zip('1234', 'abcdefg'))
[('1', 'a'), ('2', 'b'), ('3', 'c'), ('4', 'd')]
tuple(zip('1234', 'abcdefg'))
(('1', 'a'), ('2', 'b'), ('3', 'c'), ('4', 'd'))
dict(zip('1234', 'abcdefg'))
{'1': 'a', '2': 'b', '3': 'c', '4': 'd'}

元組和列表的異同點

共同點:

  • 都是有序序列,支持雙向索引。都支持count();len();sum/max/min();map/fliter/reduce/zip();+ += * * = in

不同點:

  • 元組屬有序不可變,不同於列表增、刪、查、改,只能,也就沒有append、inset、pop、remove、可認為它是常量列表
  • Python給元組進行高效優化,訪問速度快於列表,如果數據只是用來遍歷查看而不修改,優先考慮元組,同時元組讓數據更加安全
  • 元組同數字、字符串屬於不可變序列,可作為字典的鍵,而可變的列表、集合、字典永遠不能作為列表的鍵,可用hash()來哈希一下,對象可哈希則表示其可唯一,不可變
hash((1,))  # 測試元組對象
3430019387558

Signature: hash(obj, /)
Docstring:
Return the hash value for the given object.

Two objects that compare equal must also have the same hash value, but the
reverse is not necessarily true.

hash(666) # hash 數字
666
hash("hello world")  # hash 字符串
-5895774585350095353
hash([1,2,8])  # hash list
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-74-c3e4c0716b94> in <module>()
----> 1 hash([1,2,8])  # hash list


TypeError: unhashable type: 'list'
hash({'1':2, 'cj':98})  # hash dict
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-75-af1fc46d441c> in <module>()
----> 1 hash({'1':2, 'cj':98})  # hash dict


TypeError: unhashable type: 'dict'
hash({1,2,2,2,4}) # hash set
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-76-87745b5b889e> in <module>()
----> 1 hash({1,2,2,2,4}) # hash set


TypeError: unhashable type: 'set'

生成器推導式

  • 寫法上,就是(exp1 for-loop conditon)與列表推導式不同在於,生成器推導式的結果是一個生成器對象,而列表推導式返回列表
  • 惰性求值,只在需要的時候生成新元素空間占用非常少,尤其適合大數據處理場景
  • 訪問時,支持轉化為列表、元組等,可用其對象的__next__()方法或內置函數next(),或用for進行遍歷
  • 只支持正向訪問,不能再次訪問已訪問過的元素,也不支持使用下標訪問其中的元素
  • 想重新訪問,只能重新創建該生成器對象。enumerate/filter/map/zip對象也是一樣,還有yield
g = ((i + 2) ** 2 for i in range(10))  # 創建生成器對象
g
<generator object <genexpr> at 0x000000F2E6C3C7D8>
for i in g:
    print(i, end=' ')
4 9 16 25 36 49 64 81 100 121 
tuple(g) # 剛剛已經遍歷了,就不能再訪問了
()
g = ((i + 2) ** 2 for i in range(10))  # 重新創建生成器對象
g
<generator object <genexpr> at 0x000000F2E6C3C1A8>
g.__next__()
4
g.__next__()
9
next(g)  # 使用內置函數
16
x = filter(None, range(20))  # filter 對象也有同樣的特點
1 in x
True
3 in x
True
3 in x  # 不能訪問已經訪問過的元素
False
m = map(str, range(20))  # map對象也有相同的特點
'0' in m
True
'0' in m  # 不能再次訪問已經訪問過的元素
False

字典:對應關系映射

  • 字典是一個無序可變的數據類型
  • 不允許重復,無所謂,可作為鍵:數值、字符串、元組,不可作為鍵:列表、集合、字典等可變類型
  • 字典在內部維護的哈希表使得檢索操作非常快,非常高效且節約內存

字典的創建與刪除

d = {'name':'cj', 'age':22, "height":173}  # 直接創建
# 創建空字典
x = {}  
x = dict()
key = [1,2,3,4]
value = ('a','b','c','d')

x = dict(zip(key, value))
print(x)
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
d1 = dict.fromkeys(['age', 'name', 'sex'])  # 以給指定內容為 key, value 為 None
d1
{'age': None, 'name': None, 'sex': None}

Signature: dict.fromkeys(iterable, value=None, /)
Docstring: Returns a new dict with keys from iterable and values equal to value.

del d1  # 刪除字典
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-100-5c2f7f3b2a7b> in <module>()
----> 1 del d1  # 刪除字典


NameError: name 'd1' is not defined

字典元素訪問

通過dict[key]去訪問value,如不存在key則會拋出異常

d = {'name':'cj', 'age':22, "height":173}
d['name']  # 存在鍵,則會返回值
'cj'
d['xxx'] # 不存在鍵,則會拋出異常
---------------------------------------------------------------------------

KeyError                                  Traceback (most recent call last)

<ipython-input-104-9e01d6244f6b> in <module>()
----> 1 d['xxx'] # 不存在鍵,則會拋出異常


KeyError: 'xxx'

為了防止訪問出錯引發異常而崩潰,可以采用判斷結構異常處理來控制

d = {'name':'cj', 'age':22, "height":173}
if 'cj' in d:   # 先判斷 key 是否存在
    print(d['cj'])
else:
    print('Not exists.')
Not exists.
try:
    print(d['cj'])
except:
    print("Not exists.")
Not exists.
d.get('name')  # 找到則返回值
'cj'
d.get('cj', "Not exists.")  # 沒有找到則返回第二個參數值
'Not exists.'

Docstring: D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.

x = d.get('xxx')  # 沒有找到時,默認返回None, 應用:可以用來統計值的出現頻次嘛,d.get(key, 0) + 1
print(x)
None
# 統計字符出現頻次
import random
import string
x = string.ascii_letters + string.digits  # 拼接24字母(大小寫)和數字(0-9)
x
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
string = ''.join((random.choice(x) for i in range(1000)))  # 隨機生成000個字符
# string[:10]
# 統計詞頻
d = dict()

for s in string:
    
    d[s] = d.get(s, 0) + 1
    
# 查看結果
print('詞頻統計結果如下:\n')
      
for k, v in d.items():
    print(k, v)
    
詞頻統計結果如下:

P 18
V 15
2 17
d 19
g 19
e 16
R 14
y 15
x 26
D 23
N 16
0 14
B 11
I 18
Q 19
p 14
u 17
s 18
Y 23
6 21
S 15
O 15
Z 12
E 14
h 19
r 8
T 19
9 15
i 12
o 17
m 15
4 19
z 14
5 19
1 18
3 12
v 24
7 15
8 16
l 18
a 16
U 15
w 14
L 13
C 15
k 22
t 17
M 17
A 17
b 10
H 15
J 20
n 22
W 21
K 15
G 18
X 13
j 8
f 10
c 12
q 11
F 10
d = {'name':'cj', 'age':22, "height":173}
d.setdefault("sex", '男')  # 新增元素,如果存在,返回值,如果不存在,則添加key-value; 
d
{'name': 'cj', 'age': 22, 'height': 173, 'sex': '男'}

d.setdefault("sex", '男') # 新增元素,已經存在,不會覆蓋原有數據
d

Docstring: D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D

對字典對象進行迭代或者遍歷時,默認是遍歷字典的鍵
除了d.items()不算 len/ sum/ max/ min/ sorted/ enumerate /keys/ valus/ map/ filter/ in 等也遵從相同約定(key

for k in d:  # 默認是遍歷字典的鍵
    print(k, end= ' ')
name age height sex 
d.keys()  # key
dict_keys(['name', 'age', 'height', 'sex'])
d.values()
dict_values(['cj', 22, 173, '男'])
d.items()  # 明確指定遍歷字典元素 key-value
dict_items([('name', 'cj'), ('age', 22), ('height', 173), ('sex', '男')])
for k, v in d.items():
    print(k, v)
name cj
age 22
height 173
sex 男

字典元素 增、改、刪

d['love'] = 'reading'  # 字典的增、改是一樣的操作
d
{'name': 'cj', 'age': 22, 'height': 173, 'sex': '男', 'love': 'reading'}
d.update({'score':100, 'major':'marketing'})  # d.update 增加一個字典
d
{'name': 'cj',
 'age': 22,
 'height': 173,
 'sex': '男',
 'love': 'reading',
 'score': 100,
 'major': 'marketing'}

Docstring:
D.update([E, ]**F) -> None. Update D from dict/iterable E and F.
If E is present and has a .keys() method, then does: for k in E: D[k] = E[k]
If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v
In either case, this is followed by: for k in F: D[k] = F[k]

del d['age']  # 刪除字典元素  del d 刪除全部, d.clear() 清空
d
{'name': 'cj',
 'height': 173,
 'sex': '男',
 'love': 'reading',
 'score': 100,
 'major': 'marketing'}
del d['xxx']  # 刪除不存在的會報異常, 可用 選擇結構 或 異常處理 進行優化
---------------------------------------------------------------------------

KeyError                                  Traceback (most recent call last)

<ipython-input-144-379e1eeb4165> in <module>()
----> 1 del d['xxx']


KeyError: 'xxx'
d.pop('sex')  # 彈出刪除 指定元素 的值,對空字典會報異常哦
'男'

dict.pop(key) 指定刪除;dict.popitem() 隨機刪除,這個有些恐怖,我覺得有很多做恐怖游戲的用武之地

 d.popitem()  # 彈出 隨機刪除 元素的key-value,對空字典會報異常哦
('major', 'marketing')

Docstring:
D.popitem() -> (k, v), remove and return some (key, value) pair as a
2-tuple; but raise KeyError if D is empty.

集合:無序可變-元素不可重復

集合同字典的鍵一樣,數據只能包含數字、字符串、元組等不可變(可哈希)類型,不能有可變的類型如字典、列表、集合等

集合對象的創建與刪除

a = {3,4,5,5,6,2,'cj', (1,3)}  # 直接創建,會自動去重,且是無序的
a 
{(1, 3), 2, 3, 4, 5, 6, 'cj'}
a_set = set(range(8, 14))
a_set
{8, 9, 10, 11, 12, 13}
b_set = set([1,3,2,4,9,0,4,4,3,5,2,6,6,6,6,6,])  # 轉化時就自動去重了
b_set
{0, 1, 2, 3, 4, 5, 6, 9}
a = set() # 空集合
type(a)
set

集合推導式

Python具有:

  • 列表推導式
  • 生成器推導式(元組)
  • 字典推導式
  • 集合推導式
{s.strip() for s in ('she ', ',', 'i')} 
{',', 'i', 'she'}
# 生成1-500間的10個隨機數,並自動去重
import random

{random.randint(1, 500) for _ in range(10)}
{39, 47, 103, 136, 157, 174, 272, 346, 359, 431}
a = {1,2,4}
del a  # 刪除集合
a
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-161-88f0dc819981> in <module>()
----> 1 del a
      2 a


NameError: name 'a' is not defined

集合操作與運算

元素的增、刪

s = {1,2,3}
s.add(3)  # 增加元素,重復元素則自動忽略
s.add(4)
s
{1, 2, 3, 4}
s.update({2,4,5,8})  # update 增加一個集合,同字典一樣
s 
{1, 2, 3, 4, 5, 8}
s.remove('x') # 刪除一個元素,不存在就拋出異常,set.remove() 
---------------------------------------------------------------------------

KeyError                                  Traceback (most recent call last)

<ipython-input-166-50960b113aed> in <module>()
----> 1 s.remove('x') # 刪除一個元素,不存在就拋出異常,set.remove() 必須是數字


KeyError: 'x'
s.discard('ddd')  # 元素存在則刪除,不存在則忽略改操作

Docstring:
D.popitem() -> (k, v), remove and return some (key, value) pair as a
2-tuple; but raise KeyError if D is empty.

s.pop(1)  # set.pop() 隨機刪除,並返回改元素
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-177-f06e91dfbaaa> in <module>()
----> 1 s.pop(1)


TypeError: pop() takes no arguments (1 given)

集合運算

內置函數:len/ max/ min/ sum/ sorted/ map/ filter/ enumerate/() in等也適用於集合

a = {1,2,3,4,5}

b = {4,5,6,7,8}

交集 intersection

a & b # 交集  intersection
{4, 5}
a.intersection(b)
{4, 5}

並集 union

a | b   # 並集 union
{1, 2, 3, 4, 5, 6, 7, 8, 9}
a.union(b)
{1, 2, 3, 4, 5, 6, 7, 8, 9}

對稱差集 symmetric_difference

a ^ b  # a 與 b 不同的元素
{1, 2, 3, 6, 7, 8, 9}
a.symmetric_difference(b)
{1, 2, 3, 6, 7, 8, 9}

差集 difference

a - b  #  a 有而 a 沒有的元素
{1, 2, 3}
a.difference(b)
{1, 2, 3}
b - a  
{6, 7, 8, 9}
b.difference(a)  #  b 不同於 a 的元素 
{6, 7, 8, 9}

子集

a = {1,2,3}
b = {1,2,3,4}
a < b  #  a 是b的 真子集
True
{1,2} <= {1,2}  # 子集
True
a.issubset(b)  # 測試是否為子集
True

Python 之禪 需要常常閱讀

import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Python中, 字典、集合都使用哈希表來存儲元素,其查找速度非常快,關鍵字 in 作用語字典和集合時,比列表要快得很多

import random
import time

x1 = list(range(10000))
x2 = tuple(range(10000))
x3 = set(range(10000))
x4 = dict(zip(range(10000), range(10000)))
r = random.randint(0, 9999)

for i in (x4, x3, x2, x1):
    start = time.time()
    for j in range(10000000):  執行1千萬次,方便比較
        
        pass  # 執行代碼而已,增加程序運行時間, 沒什么實際作用
        
    print(type(i), 'Time used:', time.time() - start )
    





<class 'dict'> Time used: 0.5323772430419922
<class 'set'> Time used: 0.48834705352783203
<class 'tuple'> Time used: 0.47533631324768066
<class 'list'> Time used: 0.47133350372314453
import time
time.time()
1540551645.3004868

集合應用案例-電影推薦

需求:

  • 假設已經有若干用戶名字及其喜歡的電影清單
  • 現在用某用戶,已看過,並喜歡一些電影,現想找個新電影看看,又不知道看什么好,請根據已有數據給用戶做推薦

方案:

  • 根據已有數據,查找與該用戶最相似的用戶(看過並喜歡的電影與該用戶最接近的用戶)
  • 從他喜歡的電影中選取一個當前用戶還沒看過的電影,然后推薦
import random
random.randrange(1,8)
3

Signature: random.randrange(start, stop=None, step=1, _int=<class 'int'>)
Docstring:
Choose a random item from range(start, stop[, step]).

字典推導式
{'cj' + str(i): {j for j in range(5)} for i in range(5)}
{'cj0': {0, 1, 2, 3, 4},
 'cj1': {0, 1, 2, 3, 4},
 'cj2': {0, 1, 2, 3, 4},
 'cj3': {0, 1, 2, 3, 4},
 'cj4': {0, 1, 2, 3, 4}}
from random import randrange

# 其他用戶喜歡看的電影清單  用戶1:電影1

data = {'用戶' + str(i):{"film" + str(randrange(1, 10)) for j in range(randrange(15))} for i in range(10)}  # 需要好好再理解一番

# print(data)

# 需求用戶 曾經看過 並感覺不錯的電影

user = {'film1', 'film2', 'film3'}

# 查找與 需求用戶 最為相似的 用戶和他喜歡看的電影

similar_user, films = max(data.items(), key=lambda item: len(item[1] & user))




print("歷史數據:")
print('** '* 27)
for k, v in data.items():
    print(k, v, sep=':')
 
print('**'* 27)

print('和您最相似的用戶是:', similar_user)

print('他最喜歡看的電影是:', similar_user)

print('他看過的電影中,您還沒有看過的有:', films - user)  # 兩個集合的差

歷史數據:
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 
用戶0:{'film8', 'film1', 'film9'}
用戶1:{'film8', 'film4', 'film1'}
用戶2:{'film4', 'film7', 'film9', 'film2', 'film1', 'film3', 'film8', 'film6'}
用戶3:{'film2', 'film9'}
用戶4:{'film2', 'film4'}
用戶5:{'film4', 'film9', 'film1', 'film3', 'film8', 'film2'}
用戶6:{'film7', 'film4', 'film1', 'film9'}
用戶7:{'film5', 'film4', 'film7', 'film1', 'film3', 'film8', 'film6'}
用戶8:{'film5', 'film1', 'film3', 'film8', 'film2'}
用戶9:set()
******************************************************
和您最相似的用戶是: 用戶2
他最喜歡看的電影是: 用戶2
他看過的電影中,您還沒有看過的有: {'film4', 'film7', 'film9', 'film8', 'film6'}
{'cj' + str(i): {j for j in range(5)} for i in range(5)}
{'cj0': {0, 1, 2, 3, 4},
 'cj1': {0, 1, 2, 3, 4},
 'cj2': {0, 1, 2, 3, 4},
 'cj3': {0, 1, 2, 3, 4},
 'cj4': {0, 1, 2, 3, 4}}

序列解包

x, y, z = 1,2,3  # 多變量賦值
a_tuple = (False, 66.6, 'cj')  # 解包元組元素

x, y, z = a_tuple
x, y, z = range(3)
x, y, z = map(str, range(9)) # 解包元素不夠,就報錯了,不夠解呀
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-257-9e8e47dc0d96> in <module>()
----> 1 x, y, z = map(str, range(9)) # 解包元素不夠,就報錯了,不夠解呀


ValueError: too many values to unpack (expected 3)
a, b = b, a  # 直接交換兩個變量的值,而無需使用第三個中介變量
d = {'a':1, 'b':2, 'c':3}
a, b, c = d.items()
print(a,b,c)

e,f,g = d.values()  # d.keys() 也一樣
print(e,f,g)
('a', 1) ('b', 2) ('c', 3)
1 2 3

string.format()來占位,感受一下

x = ['a', 'b', 'c']

for i, v in enumerate(x):
    print("The value on the position {0} is {1}".format(i, v))  # 也沒有覺得比%s,%d,%r 好用在哪里呀
The value on the position 0 is a
The value on the position 1 is b
The value on the position 2 is c

本章小結

  • 列表是包含若干元素的有序連續內存空間,當對元素增刪時,列表對象自動進行內存擴縮,保證相鄰元素間沒有縫隙
  • 應盡量從列表尾部進行元素的追加和刪除操作,盡量不要insert()
  • 列表、元組、字符串都支持雙向索引,字典支持用“鍵”作為下標訪問元素值,集合不支持任何索引
  • 切片操作作用於列表時具有最強大的功能
  • 列表可變、元組不可變,這是一個非常本質的區別
  • 列表推導式的結果是一個列表,元組推導式的結果是一個生成器對象
  • 字典的“鍵”和集合的元素都不允許重復,並且必須是不可變數據類型
  • 關鍵字 in 可作用語列表以及其他可迭代對象,包括元組、字典、列表、集合、range對象、字符串、循環結構等(常用於)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM