01. Python3 數據類型(一)
python3 基本數據類型大致分為 可變數據類型 和 不可變數據類型 ,不可變有 Number(數字)、String(字符串)、Tuple(元組) ,可變有 List(列表)Dictionary(字典)Set(集合)
文章目錄
- 01. Python3 數據類型(一)
- Number
- 關于Number一些運算和內置函數
- 字符串
- 索引 (通用序列操作)
- 切片[左索引:右索引:步長] (通用序列操作)
- 常用方法
- 格式化方法format()
- List(列表)
- 序列 UML
- 檢驗值是否存在序列中 (通用序列操作)
- 序列的*
- 序列的+ 和 +=
- 常用方法
- 列表推導式和生成器表達式
- 易讀性
- 生成器表達式
- 列表推導同filter和map的比較
- 切片
- 對對象進行切片
- 切片原理
- 給切片賦值
- 元組
- 元組拆包
- 具名元組
- 字典
- Map UML
- 字典推導
- dict、 defaultdict 和 OrderedDict
- 用setdefault處理找不到的鍵 (用于更新操作)
- 映射的彈性鍵查詢
- 字典的變種
- 不可變映射類型
- 集合
- 集合 UML
- set 和 frozenset
- 集合字面量
- 集合推導
- 集合的操作
- dict和set的背后
- dict的實現及其導致的結果
- set的實現以及導致的結果
Number
python3 支持int、float、bool、complex(復數)
關于Number一些運算和內置函數
# /運算結果為小數
print
(
4
/
2
)
# ==>2.0
print
(
5
/
4
)
# ==>1.25
# //運算結果舍棄余數
print
(
9.0
//
4
)
# ==>2.0
print
(
9.2
//
4
)
# ==>2.0
print
(
9
//
4
)
# ==>2
# %運算保留余數
print
(
9.0
%
4
)
# ==>1.0
print
(
9.2
%
4
)
# ==>1.1999999999999993
print
(
9
%
4
)
# ==>1
# **運算為冪運算
print
(
2
**
-
1
)
# ==>0.5
# 絕對值abs(Number)
print
(
abs
(
-
3
)
)
# ==>3
# 向原點0取整
print
(
int
(
-
2.3
)
)
# ==>-2
# 四舍五入round(no_complex, 0)
print
(
round
(
3.1415
,
3
)
)
# ==>3.142
字符串
字符串是以單引號’或雙引號"括起來的任意文本,比如’abc’,"xyz"等等。
索引 (通用序列操作)
# 正索引
print
(
"abcde"
[
0
]
)
# ==>a
# 負索引,-n:倒數第n個元素
print
(
"abcde"
[
-
1
]
)
# ==>e
切片[左索引:右索引:步長] (通用序列操作)
# 切片str[m:n],m默認為0,n默認為len(str)
print
(
"abcde"
[
1
:
3
]
)
# ==>bc
print
(
"abcde"
[
1
:
]
)
# ==>bcde
print
(
"abcde"
[
:
2
]
)
# ==>ab
print
(
'abcde'
[
0
:
5
:
2
]
)
# ==>ace
常用方法
# 大小寫轉換
print
(
"Python"
.
upper
(
)
)
# ==>PYTHON
print
(
"Python"
.
lower
(
)
)
# ==>python
print
(
"hello world"
.
capitalize
(
)
)
# ==>Hello world
print
(
"hello world"
.
title
(
)
)
# ==>Hello World
# 非重疊字符串的數量
print
(
"ablllabllab"
.
count
(
"ll"
)
)
# ==>2
# 字符串查找
print
(
"hihihi"
.
find
(
"hi"
)
)
# ==>0
print
(
"hihihi"
.
rfind
(
"hi"
)
)
# ==>4
# 字符串替換所有
print
(
"To a To b"
.
replace
(
'To'
,
'to'
)
)
# ==>to a to b
# 首尾去除,默認空格
print
(
"first-first-end"
.
strip
(
'find'
)
)
# ==>rst-first-e
print
(
"first-first-end"
.
strip
(
'first-'
)
)
# ==>end
print
(
"first-end-end"
.
rstrip
(
'-end'
)
)
# ==>first
# 用于輸出的對齊,默認填充空格
print
(
"hello"
.
ljust
(
9
,
'-'
)
+
"hello"
.
center
(
9
,
'+'
)
+
"hello"
.
rjust
(
9
,
'-'
)
)
# ==>hello----++hello++----hello
格式化方法format()
List(列表)
列表是一種序列,因此索引和切片與字符串類似
序列 UML
檢驗值是否存在序列中 (通用序列操作)
print
(
2
in
[
1
,
2
,
3
,
4
]
)
# ==>True
print
(
'bc'
in
'abcde'
)
# ==>True
序列的*
# 一個包含 3 個列表的列表, 嵌套的 3 個列表各自有 3 個元素來代表井字游戲的一行方塊
board
=
[
[
'_'
]
*
3
for
i
in
range
(
3
)
]
# [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
board
[
1
]
[
2
]
=
'X'
# [['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]
# *的一個特性,復制的是引用
weird_board
=
[
[
'_'
]
*
3
]
*
3
# [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
weird_board
[
1
]
[
2
]
=
'O'
# [['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']]
序列的+ 和 +=
l1
=
[
1
,
2
,
3
,
4
,
5
]
l2
=
l1
# +操作是先將[1, 2, 3, 4, 5]和[6, 7, 8]相加,將結果的引用賦值給l2
l2
=
l2
+
[
6
,
7
,
8
]
print
(
l1
)
# ==>[1, 2, 3, 4, 5]
print
(
l2
)
# ==>[1, 2, 3, 4, 5, 6, 7, 8]
print
(
id
(
l1
)
==
id
(
l2
)
)
# ==>False
l1
=
[
1
,
2
,
3
,
4
,
5
]
l2
=
l1
# +=操作是就地在l2后面加[6, 7, 8]
l2
+=
[
6
,
7
,
8
]
print
(
l1
)
# ==>[1, 2, 3, 4, 5, 6, 7, 8]
print
(
l2
)
# ==>[1, 2, 3, 4, 5, 6, 7, 8]
print
(
id
(
l1
)
==
id
(
l2
)
)
# ==>True
常用方法
l1
=
[
'1'
,
'2'
,
'3'
,
'4'
,
'1'
]
l1
.
count
(
'1'
)
# 統計某個元素出現的次數
l1
.
index
(
'1'
)
# 找出某個元素的第一次出現的位置
l1
.
reverse
(
)
# 將元素進行反轉
l1
.
sort
(
reverse
=
True
)
# 對列表進行反向排序,列表被改變,返回值是空
l1
.
append
(
'5'
)
# 向末尾添加一個元素
l1
.
insert
(
3
,
'6'
)
# 向指定索引位置添加一個元素
l1
.
extend
(
[
'1'
,
'2'
]
)
# 向末尾添加,等同于 li + ['1','2']
l1
.
pop
(
3
)
# 刪除指定索引位置的一個元素,默認末尾
l1
.
remove
(
'1'
)
# 移除列表中的第一個匹配元素
l1
.
clear
(
)
# 清空所有元素
# split和join
print
(
"1,2,3,4,5"
.
split
(
','
)
)
# ==>['1', '2', '3', '4', '5']
# join參數中的元素不能為數字
print
(
","
.
join
(
[
'1'
,
'2'
,
'3'
,
'4'
,
'5'
]
)
)
# ==>1,2,3,4,5
列表推導式和生成器表達式
列表推導是構建列表(list) 的快捷方式, 而生成器表達式則可以用來創建其他任何類型的序列。 如果你的代碼里并不經常使用它們, 那么很可能你錯過了許多寫出可讀性更好且更高效的代碼的機會。
易讀性
# 把一個字符串變成 Unicode 碼位的列表
symbols
=
'$¢£¥€¤'
code
=
[
]
for
symbol
in
symblos
:
codes
.
append
(
ord
(
symbol
)
)
# 等價于
symbols
=
'$¢£¥€¤'
code
=
[
ord
(
symbol
)
for
symbol
in
symbols
]
生成器表達式
雖然也可以用列表推導來初始化元組、 數組或其他序列類型, 但是生成器表達式是更好的選擇。 這是因為生成器表達式背后遵守了迭代器協議, 可以逐個地產出元素, 而不是先建立一個完整的列表, 然后再把這個列表傳遞到某個構造函數里。 前面那種方式顯然能夠節省內存。
生成器表達式的語法跟列表推導差不多, 只不過把方括號換成圓括號而已。
symbols
=
'$¢£¥€¤'
tuple
(
ord
(
symbol
)
for
symbol
in
symbols
)
[
ord
(
symbol
)
for
symbol
in
symbols
if
ord
(
symbol
)
>
0
]
列表推導同filter和map的比較
filter 和 map 合起來能做的事情, 列表推導也可以做, 而且還不需要借助難以理解和閱讀的 lambda 表達式。
# 選出所有大于127的Unicode 碼位
symbols
=
'$¢£¥€¤'
beyond_ascii
=
list
(
filter
(
lambda
c
:
c
>
127
,
map
(
ord
,
symbols
)
)
)
# beyond_ascii==>[162, 163, 165, 8364, 164]
# 等價于
beyond_ascii
=
[
ord
(
s
)
for
s
in
symbols
if
ord
(
s
)
>
127
]
切片
像列表(list)、元組(tuple) 和字符串(str) 這類序列類型都支持切片操作, 但是實際上切片操作比人們所想象的要強大很多。
對對象進行切片
用
s[a:b:c]
的形式對 s 在 a 和 b之間以 c 為間隔取值。 c 的值還可以為負, 負值意味著反向取值。
s
=
'bicycle'
print
(
s
[
:
:
3
]
)
# ==>bye
print
(
s
[
:
:
-
1
]
)
# ==>elcycib
print
(
s
[
:
:
-
2
]
)
# ==>eccb
切片原理
a:b:c
這種用法只能作為索引或者下標用在 [] 中來返回一個切片對象: slice(a, b, c)。
對
seq[start:stop:step]
進行求值的時候, Python 會調用
seq.__getitem__(slice(start, stop, step))
。
class
MySeq
:
def
__getitem__
(
self
,
index
)
:
return
index
s
=
MySeq
(
)
print
(
s
[
1
]
)
# ==>1
print
(
s
[
1
:
4
]
)
# ==>slice(1, 4, None)
print
(
s
[
1
:
4
:
2
,
7
:
9
]
)
# ==>(slice(1, 4, 2), slice(7, 9, None))
通過審查 slice 它有 start、 stop 和 step 數據屬性, 以及indices 方法。
# S.indices(len) -> (start, stop, stride)
# 給定長度為 len 的序列, 計算 S 表示的擴展切片的起始(start)和結尾(stop) 索引, 以及步幅(stride) 。 超出邊界的索引會被截掉, 這與常規切片的處理方式一樣。
# 假設有個長度為 5 的序列, 例如 'ABCDE'
# 'ABCDE'[:10:2] 等同于 'ABCDE'[0:5:2]
slice
(
None
,
10
,
2
)
.
indices
(
5
)
# ==>(0, 5, 2)
# 'ABCDE'[-3:] 等同于 'ABCDE'[2:5:1]
slice
(
-
3
,
None
,
None
)
.
indices
(
5
)
# ==>(2, 5, 1)
給切片賦值
如果把切片放在賦值語句的左邊, 或把它作為 del 操作的對象, 我們就可以對序列進行嫁接、 切除或就地修改操作。
ps : 賦值語句右邊必須是一個可迭代對象
l
=
list
(
range
(
10
)
)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l
[
2
:
5
]
=
[
20
,
30
]
# [0, 1, 20, 30, 5, 6, 7, 8, 9]
del
l
[
5
:
7
]
# [0, 1, 20, 30, 5, 8, 9]
l
[
3
:
:
2
]
=
[
11
,
22
]
# [0, 1, 20, 11, 5, 22, 9]
元組
元組除了用作不可變的列表, 它還可以用于沒有字段名的記錄。
# 經緯度
lax_coordinates
=
(
33.9425
,
-
118.408056
)
# 東京市的一些信息:市名、年份、人口(單位: 百萬)、人口變化(單位: 百分比)和面積(單位: 平方千米)。
city
,
year
,
pop
,
chg
,
area
=
(
'Tokyo'
,
2003
,
32450
,
0.66
,
8014
)
元組拆包
# 簡單的拆包
lax_coordinates
=
(
33.9425
,
-
118.408056
)
latitude
,
longitude
=
lax_coordinates
# 元組拆包
# 交換變量的值
a
,
b
=
1
,
2
a
,
b
=
b
,
a
# 用 * 運算符把一個可迭代對象拆開作為函數的參數
# 20除8 等于 2余4
print
(
divmod
(
20
,
8
)
)
#==>(2, 4)
t
=
(
20
,
8
)
print
(
divmod
(
*
t
)
)
#==>(2, 4)
# 使用_占位符
_
,
b
=
(
1
,
2
)
print
(
b
)
#==>2
# Python3 在平行賦值中使用*args
a
,
b
,
*
rest
=
range
(
5
)
# (0, 1, [2, 3, 4])
a
,
b
,
*
rest
=
range
(
3
)
# (0, 1, [2])
a
,
b
,
*
rest
=
range
(
2
)
# (0, 1, [])
a
,
*
body
,
c
,
d
=
range
(
5
)
# (0, [1, 2], 3, 4)
*
head
,
b
,
c
,
d
=
range
(
5
)
# ([0, 1], 2, 3, 4)
# 嵌套元組拆包
(
a
,
b
,
(
c
,
d
)
)
=
(
1
,
2
,
(
3
,
4
)
)
具名元組
collections.namedtuple 是一個工廠函數, 它可以用來構建一個帶字段名的元組和一個有名字的類——這個帶名字的類對調試程序有很大幫助
from
collections
import
namedtuple
City
=
namedtuple
(
'City'
,
'name country population coordinates'
)
tokyo
=
City
(
'Tokyo'
,
'JP'
,
36.933
,
(
35.689722
,
139.691667
)
)
print
(
tokyo
)
# ==>City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722,139.691667))
print
(
tokyo
.
population
)
# ==>36.933
print
(
tokyo
.
coordinates
)
# ==>(35.689722, 139.691667)
字典
字典這個數據結構活躍在所有 Python 程序的背后, 即便你的源碼里并沒有直接用到它。
Map UML
字典推導
字典推導(dictcomp) 可以從任何以鍵值對作為元素的可迭代對象中構建出字典。
DIAL_CODES
=
[
(
86
,
'China'
)
,
(
91
,
'India'
)
,
(
1
,
'United States'
)
,
(
62
,
'Indonesia'
)
,
(
55
,
'Brazil'
)
,
(
92
,
'Pakistan'
)
,
(
880
,
'Bangladesh'
)
,
(
234
,
'Nigeria'
)
,
(
7
,
'Russia'
)
,
(
81
,
'Japan'
)
,
]
country_code
=
{
country
:
code
for
code
,
country
in
DIAL_CODES
}
# {'China': 86, 'India': 91, 'Bangladesh': 880, 'United States': 1,'Pakistan': 92,'Japan': 81, 'Russia': 7, 'Brazil': 55, 'Nigeria':234, 'Indonesia': 62}
x
=
{
code
:
country
.
upper
(
)
for
country
,
code
in
country_code
.
items
(
)
if
code
<
66
}
# {1: 'UNITED STATES', 55: 'BRAZIL', 62: 'INDONESIA', 7: 'RUSSIA'}
dict、 defaultdict 和 OrderedDict
后面兩個數據類型是 dict 的變種, 位于 collections 模塊內。
不同方法
dict | defaultdict | OrderedDict | 說明 | |
---|---|---|---|---|
d.__copy__()
|
√ |
用于支持
copy.copy
|
||
d.default_factory
|
√ |
在
__missing__
函數中被調用的函數, 用以給未找到的元素設置值
|
||
d.__missing__(k)
|
√ |
當
__getitem__
找不到對應鍵的時候, 這個方法會被調用
|
||
d.move_to_end(k,[last])
|
√ | 把鍵為 k 的元素移動到最靠前或者最靠后的位置(last 的默認值是 True) | ||
d.__reversed__()
|
√ | 返回倒序的鍵的迭代器 |
- default_factory 并不是一個方法, 而是一個可調用對象( callable) , 它的值在defaultdict 初始化的時候由用戶設定。
相同方法
方法 | 說明 |
---|---|
d.clear()
|
移除所有元素 |
d.__contains__(k)
|
檢查 k 是否在 d 中 |
d.copy()
|
淺復制 |
d.fromkeys(it,[initial])
|
將迭代器 it 里的元素設置為映射里的鍵, 如果有 initial 參數,
就把它作為這些鍵對應的值(默認是 None) |
d.get(k,[default])
|
沒有鍵 k, 則返回 None 或者default |
d.items()
|
返回 d 里所有的鍵值對 |
d.__iter__()
|
獲取鍵的迭代器 |
d.keys()
|
獲取所有的鍵 |
d.pop(k, [defaul])
|
返回鍵 k 所對應的值, 然后移除這個鍵值對。 如果沒有這
個鍵,返回 None 或者 defaul |
d.popitem()
|
隨機返回一個鍵值對并從字典里移除它 |
d.setdefault(k,[default])
|
若字典里有鍵k, 則把它對應的值設置為 default,
然后返回這個值; 若無, 則讓 d[k] =default, 然后返回 default |
d.update(m,[**kargs])
|
m 可以是映射或者鍵值對迭代器, 用來更新 d 里對應的條目 |
d.values()
|
返回字典里的所有值 |
- OrderedDict.popitem() 會移除字典里最先插入的元素( 先進先出) ; 同時這個方法還有一個可選的 last 參數, 若為真, 則會移除最后插入的元素( 后進先出) 。
用setdefault處理找不到的鍵 (用于更新操作)
當字典 d[k] 不能找到正確的鍵的時候, Python 會拋出異常, 這個行為符合 Python 所信奉的“快速失敗”哲學。
my_dict
.
setdefault
(
key
,
[
]
)
.
append
(
new_value
)
# 跟這樣寫
if
key
not
in
my_dict
:
my_dict
[
key
]
=
[
]
my_dict
[
key
]
.
append
(
new_value
)
#二者的效果是一樣的,只不過后者至少要進行兩次鍵查詢——如果鍵不存在的話,就是三次,用 setdefault 只需要一次就可以完成整個操作
映射的彈性鍵查詢
有時候為了方便起見, 就算某個鍵在映射里不存在, 我們也希望在通過這個鍵讀取值的時候能得到一個默認值。
**defaultdict: 處理找不到的鍵的一個選擇 **
在用戶創建 defaultdict 對象的時候, 就需要給它配置一個為找不到的鍵創造默認值的方法。
'''
比如,我們新建了這樣一個字典:dd = defaultdict(list),如果鍵'new-key' 在 dd 中還不存在的話,表達式 dd['new-key'] 會按照以下的步驟來行事。
(1) 調用 list() 來建立一個新列表。
(2) 把這個新列表作為值, 'new-key' 作為它的鍵, 放到 dd 中。
(3) 返回這個列表的引用。
而這個用來生成默認值的可調用對象存放在名為 default_factory 的實例屬性里。
'''
d
=
collections
.
defaultdict
(
list
)
print
(
d
.
default_factory
)
# ==>
print
(
d
[
'key'
]
)
# ==>[]
-
defaultdict 里的
default_factory
只會在__getitem__
里被調用,get(key)
則會返回 None。
特殊方法
__missing__
所有的映射類型在處理找不到的鍵的時候, 都會牽扯到
__missing__
方法。 這也是這個方法稱作“missing”的原因。 雖然基類 dict 并沒有定義這個方法, 但是 dict 是知道有這么個東西存在的。
# 在查詢的時候把非字符串的鍵轉換為字符串
class
StrKeyDict0
(
dict
)
:
def
__missing__
(
self
,
key
)
:
if
isinstance
(
key
,
str
)
:
raise
KeyError
(
key
)
return
self
[
str
(
key
)
]
def
get
(
self
,
key
,
default
=
None
)
:
try
:
return
self
[
key
]
except
KeyError
:
return
default
def
__contains__
(
self
,
key
)
:
return
key
in
self
.
keys
(
)
or
str
(
key
)
in
self
.
keys
(
)
-
__missing__
方法只會被__getitem__
調用(比如在表達式 d[k] 中) -
像
k in my_dict.keys()
這種操作在 Python 3 中是很快的, 而且即便映射類型對象很龐大也沒關系。 這是因為dict.keys()
的返回值是一個“視圖”。 視圖就像一個集合, 而且跟字典類似的是, 在視圖里查找一個元素的速度很快。
字典的變種
**collections.OrderedDict **
這個類型在添加鍵的時候會保持順序, 因此鍵的迭代次序總是一致的。 OrderedDict 的
popitem
方法默認刪除并返回的是字典里的最后一個元素, 但是如果像
my_odict.popitem(last=False)
這樣調用它, 那么它刪除并返回第一個被添加進去的元素。
**collections.ChainMap **
該類型可以容納數個不同的映射對象, 然后在進行鍵查找操作的時候, 這些對象會被當作一個整體被逐個查找, 直到鍵被找到為止。 這個功能在給有嵌套作用域的語言做解釋器的時候很有用, 可以用一個映射對象來代表一個作用域的上下文。
**collections.Counter **
這個映射類型會給鍵準備一個整數計數器。 每次更新一個鍵的時候都會增加這個計數器。 所以這個類型可以用來給可散列表對象計數, 或者是當成多重集來用——多重集合就是集合里的元素可以出現不止一次。 Counter 實現了 + 和 - 運算符用來合并記錄, 還有像
most_common([n])
這類很有用的方法。
ct
=
collections
.
Counter
(
'abracadabra'
)
# Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
ct
.
update
(
'aaaaazzz'
)
# Counter({'a': 10, 'z': 3, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
ct
.
most_common
(
2
)
# [('a', 10), ('z', 3)]
**colllections.UserDict **
這個類其實就是把標準 dict 用純 Python 又實現了一遍。跟 OrderedDict、 ChainMap 和 Counter 這些開箱即用的類型不同, UserDict 是讓用戶繼承寫子類的。而更傾向于從 UserDict 而不是從 dict 繼承的主要原因是, 后者有時會在某些方法的實現上走一些捷徑, 導致我們不得不在它的子類中重寫這些方法, 但是 UserDict 就不會帶來這些問題。
不可變映射類型
從 Python 3.3 開始, types 模塊中引入了一個封裝類名叫MappingProxyType。 如果給這個類一個映射, 它會返回一個只讀的映射視圖。 雖然是個只讀視圖, 但是它是動態的。 這意味著如果對原映射做出了改動, 我們通過這個視圖可以觀察到, 但是無法通過這個視圖對原映射做出修改。
d
=
{
1
:
'A'
}
d_proxy
=
MappingProxyType
(
d
)
print
(
d_proxy
[
1
]
)
# ==>A
# 不可修改
d_proxy
[
2
]
=
'x'
# TypeError: 'mappingproxy' object does not support item assignment
集合
“集”這個概念在 Python 中算是比較年輕的, 同時它的使用率也比較低。
集合 UML
set 和 frozenset
-
set無序排序且不重復,是可變的,有add(),remove()等方法。
-
frozenset是凍結的集合,它是不可變的,存在哈希值,好處是它可以作為字典的key,也可以作為其它集合的元素。缺點是一旦創建便不能更改,沒有add,remove方法。
集合字面量
除空集之外, 集合的字面量——{1}、 {1, 2}, 等等——看起來跟它的數學形式一模一樣。 如果是空集, 那么必須寫成 set() 的形式。
- 只是寫成 {} 的形式, 跟以前一樣, 你創建的其實是個空字典。
集合推導
s
=
{
chr
(
i
)
for
i
in
range
(
32
,
40
)
}
# {'!', '#', '"', '$', '%', "'", ' ', '&'}
集合的操作
集合的數學運算 :
數學符號 | Python運算符 | 描述 |
---|---|---|
S ∩ Z | s & z | s 和 z 的交集 |
S ∪ Z | s | z | s 和 z 的并集 |
S - Z | s - z | s 和 z 的差集, 或者叫作相對補集 |
S △ Z | s ^ z | s 和 z 的對稱差集 |
集合的比較運算符 :
數學符號 | Python運算符 | 描述 |
---|---|---|
e ∈ S | e in s | 元素 e 是否屬于 s |
S ? Z | s <= z | s 是否為 z 的子集 |
S ? Z | s < z | s 是否為 z 的真子集 |
S ? Z | s >= z | s 是否為 z 的父集 |
S ? Z | s > z | s 是否為 z 的真父集 |
dict和set的背后
想要理解 Python 里字典和集合類型的長處和弱點, 它們背后的散列表是繞不開的一環。
dict的實現及其導致的結果
-
鍵必須是可散列的
-
支持
hash()
函數, 并且通過__hash__()
方法所得到的散列值是不變的。 -
支持通過
__eq__()
方法來檢測相等性。 -
若
a == b
為真, 則hash(a) == hash(b)
也為真。
-
支持
-
字典在內存上的開銷巨大
- 字典使用了散列表, 而散列表又必須是稀疏的, 這導致它在空間上的效率低下。
- 如果需要存放數量巨大的記錄, 那么放在由元組或是具名元組構成的列表中會是比較好的選擇 。
-
鍵查詢很快
- dict 的實現是典型的空間換時間: 字典類型有著巨大的內存開銷, 但它們提供了無視數據量大小的快速訪問——只要字典能被裝在內存里。
-
鍵的次序取決于添加順序
- 往 dict 里添加新鍵而又發生散列沖突的時候, 新鍵可能會被安排存放到另一個位置。
-
往字典里添加新鍵可能會改變已有鍵的順序
- 無論何時往字典里添加新的鍵, Python 解釋器都可能做出為字典擴容的決定。 這個過程中可能會發生新的散列沖突, 導致新散列表中鍵的次序變化。
ps: 在 Python 3 中, .keys()、 .items() 和 .values() 方法返回的都是字典視圖。
set的實現以及導致的結果
set 和 frozenset 的實現也依賴散列表, 但在它們的散列表里存放的只有元素的引用 。
上面所提到的字典和散列表的幾個特點, 對集合來說幾乎都是適用的。
- 集合里的元素必須是可散列的。
- 集合很消耗內存。
- 可以很高效地判斷元素是否存在于某個集合。
- 元素的次序取決于被添加到集合里的次序。
- 往集合里添加元素, 可能會改變集合里已有元素的次序。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
