5-python的封裝與結構 - set集合
目錄
- 1 封裝與解構
- 1.1 封裝
- 1.2 解構
- 1.3 Python3的解構
- 2 set類型
- 2.1 set的定義
- 2.2 set的基本操作
- 2.2.1 增加元素
- 2.2.2 刪除元素
- 2.2.3 修改元素
- 2.2.4 成員判斷
- 2.3 set小結
- 3 集合
- 3.1 集合運算
- 3.2 並集
- 3.3 交集
- 3.3 差集
- 3.4 對稱差集
- 3.5 集合的其他運算
1 封裝與解構
????????封裝與解構屬於Python語言的一種特性,它使用起來很像其他語言中的"逗號表達式"
,但內部原理是不同的,在某些場景下:比如變量交換復制時使用,顯得非常優雅。
1.1 封裝
????????封裝故名思議就是裝箱,把多個值使用逗號分隔,組合在一起,本質上來看,其返回的是一個元組,只是省略了小括號。(一定要區別與C語言的逗號表達式)
In [91]: t1 = (1,2) # 定義一個元組 In [92]: t2 = 1,2 # 省略括號,其內部還是會封裝成元組 In [93]: t1 Out[93]: (1, 2) In [94]: t2 Out[94]: (1, 2) In [95]: type(t1) Out[95]: tuple In [96]: type(t2) Out[96]: tuple
1.2 解構
????????解構,解構,就是把箱子解開,在Python中表示從線性結構中把元素解開,並且順序的賦值給其他變量,需要註意的是,解構時接受元素的變量,需要放在等式的左邊,並且數量要和右邊解開的元素的個數一致。
In [97]: t1 Out[97]: (1, 2) In [98]: a,b = t1 # 表示把1賦給a,把2賦給b In [99]: a Out[99]: 1 In [100]: b Out[100]: 2 In [101]: a,b,c = t1 # 當接受元素的變量多余解構的元素時,會提示ValueError,反之相同 --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-101-2e8ad53e5fc7> in <module> ----> 1 a,b,c = t1 ValueError: not enough values to unpack (expected 3, got 2) In [102]:
1.3 Python3的解構
????????了解了封裝與解構,那麽回想一下當我們需要進行變量交換的時候,是否可以通過封裝與解構進行優化呢?當我們在其他語言中進行a,b變量的值的交換,我們需要一個中間變量temp,即:a = temp,a = b,b = temp
,在Python中我們可以省略。
>>> a = 1
>>> b = 200
>>> a,b = b,a # 這樣就完成了變量的交換了,是不是很方便
>>> a
200
>>> b
1
>>>
為什麽可以使用這種騷操作,是因為Python在進行變量賦值時,會先計算等式右邊的表達式,封裝起來,然後再進行解構,賦給對應位置上的變量。並且還提供了其他更便捷的方法比如*號。
*號
: 使用方式為:*變量名
,貪婪的吸收解構的元素形成一個列表,無論能否吸收,都會返回一個列表。_號
:表示丟棄一個變量(實際上是使用_
接受變量,但是使用這麽一個符號,就表示我們不想用它)
In [1]: t = list(range(5))
In [2]: t
Out[2]: [0, 1, 2, 3, 4]
In [3]: head,*mid,tail = t
In [4]: head
Out[4]: 0
In [5]: mid
Out[5]: [1, 2, 3]
In [6]: tail
Out[6]: 4
需要註意的是:
- *變量名,這種格式不能單獨使用
- 也不能多個*變量名,連續使用(因為從原理上看,兩個、*變量名連起來使用,會引起歧義,所以Python禁止了這種寫法)
- *_這種格式,可以收集足夠多的元素丟棄
# 1 從[1,(2,3,4),5]中取出4來
>>> _,(*_,a),_ = [1,(2,3,4),5]
>>> a
>>> 4
# 環境變量JAVA_HOME=/usr/bin/java,返回環境變量名和路徑
>>> env,path = 'JAVA_HOME=/usr/bin/java'.split('=')
>>> env,path
>>> ('JAVA_HOME','/usr/bin/java')
或者
In [9]: env, _, path = 'JAVA_HOME=/usr/bin/java'.partition('=')
In [10]: env,path
Out[10]: ('JAVA_HOME', '/usr/bin/java')
解構是Python提供的很好的功能,可以方便的提取復雜的數據結構的值,配置_使用時,會更加便捷。
2 set類型
????????集合set在Python中是一個非常重要的非線性結構
,它使用{}
表示,用三個詞總結集合的特點就是:可變的
、無序的
、不重復
。它的官方解釋如下:
- set是一個無序的,不同的
可hash對象
組成的集。 - 常用來進行成員測試,在一個序列中去掉重復的對象,和進行數學上的計算,比如
交集(intersection)
、並集(union)
、差集(difference)
、對稱差集(symmetric difference)
等。 - 和其他容器類型相似,在一個無序的集合中支持
x in set
,len(set)
,for x in set
等操作。 set不會記錄元素的位置以及元素加入集合的順序,所以set不支持
索引
,切片
或者其他的類序列的操作。什麽是可hash對象,可以簡單的理解為可以被hash()計算的對象,在Python中,可hash對象是不可變類型的,比如tuple, str, int, 等等。
2.1 set的定義
????????Python提供了兩種定義一個集合的方式,set()
和 set(iterable)
,他們的用法如下:
set() -> new empty set object --> 返回一個空的set對象
set(iterable) -> new set object --> 返回一個set對象,元素有iterable填充
例如:
In [44]: s1 = set()
In [45]: s2 = set(range(5)) # {0, 1, 2, 3, 4}
In [46]: s3 = set(list(range(10))) # 外面使用list進行轉換,多此一舉,{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
In [47]: s4 = {} # 這種方式實際上是創建了一個字典
In [48]: s4
Out[48]: {}
In [50]: type(s4)
Out[50]: dict
In [51]: s5 = {(1,3),3,'a'}
In [52]: s6={[1,2],(1,2,),1,2} # list屬於不可hash對象,所以無法添加到set中去
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-52-237c72203405> in <module>
----> 1 s6={[1,2],(1,2,),1,2}
TypeError: unhashable type: 'list'
In [53]:
2.2 set的基本操作
????????set是可變的類型,那就意味著,我們可以對set進行增加、刪除、修改等操作。
2.2.1 增加元素
????????set提供了兩種定義一個集合的方式,add
和 update
,他們的用法如下:
s.add() --> None --> 在集合s中添加一個元素,如果元素存在,則什麽都不做(去重特性)。(就地修改)
s.update(*other) --> None --> 把*others個可叠代可hash對象,和s進行並集,然後賦給s。(就地修改)
例
In [62]: s
Out[62]: {1, 2, 3}
In [63]: s.add('abc') # 把'abc'當作一個元素添加進去
In [64]: s
Out[64]: {1, 2, 3, 'abc'}
In [65]: s.add((1,2,3)) # 把(1,2,3) 當作一個元素添加進去
In [66]: s
Out[66]: {(1, 2, 3), 1, 2, 3, 'abc'}
In [67]: s.update(range(5),'abcdef',[5,6,7,8]) # 多個可叠代可hash對象取並集
In [68]: s
Out[68]: {(1, 2, 3), 0, 1, 2, 3, 4, 5, 6, 7, 8, 'a', 'abc', 'b', 'c', 'd', 'e', 'f'}
2.2.2 刪除元素
????????set提供了多種定義一個集合的方式,比如 remove
,pop
,他們的用法如下:
s.remove() --> None --> 在集合s中刪除一個元素,這個元素必須存在集合s中,否則會報KeyError異常
s.pop() --> item --> 在集合s中隨便彈出一個元素,並返回元素的本身,如果集合本身為空,那麽會提示KeyError異常
s.discard(elem) --> None --> 在集合s中刪除一個元素,如果元素不存在集合中,那麽什麽也不做
s.clear() --> None --> 清空集合
例
In [71]: s
Out[71]: {(1, 2, 3), 0, 1, 2, 3, 4, 5, 6, 7, 8, 'a', 'abc', 'b', 'c', 'd', 'e', 'f'}
In [72]: s.remove(0)
In [73]: s
Out[73]: {(1, 2, 3), 1, 2, 3, 4, 5, 6, 7, 8, 'a', 'abc', 'b', 'c', 'd', 'e', 'f'}
In [74]: s.remove(1000) # 不存在集合內的元素,刪除會報異常
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-74-9d9da17ab719> in <module>
----> 1 s.remove(1000)
KeyError: 1000
In [76]: s
Out[76]: {(1, 2, 3), 1, 2, 3, 4, 5, 6, 7, 8, 'a', 'abc', 'b', 'c', 'd', 'e', 'f'}
In [77]: s.pop()
Out[77]: 1
In [78]: s
Out[78]: {(1, 2, 3), 2, 3, 4, 5, 6, 7, 8, 'a', 'abc', 'b', 'c', 'd', 'e', 'f'}
In [82]: s1
Out[82]: set()
In [84]: s1.pop() # 空集合會報異常
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-84-095118de218b> in <module>
----> 1 s1.pop()
KeyError: 'pop from an empty set'
In [85]: s
Out[85]: {(1, 2, 3), 4, 5, 6, 7, 8, 'a', 'abc', 'b', 'c', 'd', 'e', 'f'}
In [86]: s.discard(1000) # 直接刪除,不會返回
In [89]: s.discard(4)
In [90]: s
Out[90]: {(1, 2, 3), 5, 6, 7, 8, 'a', 'abc', 'b', 'c', 'd', 'e', 'f'}
In [92]: s.clear()
In [93]: s
Out[93]: set()
2.2.3 修改元素
上來我們需要先想一個問題,為什麽要修改set呢?修改的本質是什麽?
- 修改的本質其實就是找到這個元素,刪除,然後在加入新的元素
- 由於集合是非線性結構,所以無法被索引
但是set是容器,可以被叠代
所以set不能像list那樣,通過索引修改元素,因為它無序的特性,修改其實等同於刪除、再添加而已。
2.2.4 成員判斷
我們說既然set是容器,那麽我們就可以對容器內的元素進行判斷,那麽就需要使用成員判斷符 in
和 not in
了。
- in: x in s, 判斷元素x是否是在集合s中,返回bool類型
- not in : x not in s, 判斷元素x不在集合s中,返回bool類型
In [95]: s = set(range(20))
In [96]: 1 in s
Out[96]: True
In [97]: 10000 not in s
Out[97]: True
我們知道在list,str這種
線性結構
中進行成員判斷
時,它的時間復雜度是O(n)
的,因為需要遍歷,但是在set中就很簡單了,它只需要把要判斷的元素進行hash,找到set中對應的門牌號,把裏面的數據拽出來,看看是不是相同。 這種操作通常都是O(1)
的,所以在set中,成員判斷效率很高
,當然在dict類型
中,也是如此。
2.3 set小結
????????線性結構的查詢時間復雜度是O(n)
,即隨著數據規模的這不過大而增加耗時,set、dict等結構,內部使用的是hash值作為key,時間復雜度可以做到O(1)
查詢時間和數據規模無關,在python中可hash對象有(都屬於不可變類型)
- 數值類型int、float、complex
- 布爾值True、False
- 字符串String、Bytes
- 元組tuple
- None
3 集合
????????簡單來說,所謂的一個集合,就是將數個對象歸類而分成為一個或數個形態各異的大小整體。 一般來講,集合是具有某種特性的事物的整體,或是一些確認對象的匯集。構成集合的事物或對象稱作元素或是成員。集合的元素可以是任何事物,可以是人,可以是物,也可以是字母或數字等。 (此解釋來自於維基百科)
- 全集:所有元素的結合。例如實數集,所有實數組成的集合就是實數集
- 子集subset和超集superset: 一個集合A所有的元素都在另一個集合B內,A是B的子集,B是A的超集
- 真子集和真超集:A是B的子集,且A不等於B,A就是B的真子集,B就是A的真超集
- 並集:多個集合合並的結果
- 交集:多個集合的公共部分
差集:集合中除去和其他集合共有的部分
這些是小學數學基礎概念哦,兄弟們。
3.1 集合運算
????????通過集合運算,我們可以方便的對求出集合的差集、並集等,Python的集合除了提供了大量的集合運算方法還提供了不少的特殊符號用來表示集合運算。
3.2 並集
????????將集合A和集合B所有元素合並在一起,組成的集合稱為集合A和集合B的並集
s.union(*other) --> new set object --> 把多個集合和集合s進行合並,返回一個新的集合對象
--> 使用 | 表示
s.update(*other) --> None --> 把*others個可叠代可hash對象,和s進行並集,然後賦給s。(就地修改)
--> 使用 != 表示
3.3 交集
????????集合A和集合B,由所有屬於A且屬於B的元素組成的集合。
s.intersection(*other) --> new set object --> 返回多個集合的交集
--> 使用 & 表示
s.intersection_update(*other) --> None --> 獲取多個集合的交集,就地進行修改
--> 使用 &= 表示
3.3 差集
????????集合A和B,由所有屬於A且不屬於B的元素組成的集合。
s.difference(*others) --> new set object --> 返回集合s和其他多個集合的差集
--> 使用 - 表示
s.difference_update(*other) --> None --> 返回集合s和其他多個集合的差集,就地進行修改
--> 使用 -= 表示
3.4 對稱差集
????????不屬於集合A和集合B交集的其他元素組成的集合,數學表達式為:(A-B) U (B-A)。
s.symmetric_difference(*other) --> new set object --> 返回和另一些集合的對稱差集
--> 使用 ^ 表示
s.symmetric_difference_update --> None --> 返回和另一些集合的對稱差集,就地修改
--> 使用 ^= 表示
3.5 集合的其他運算
s.issubset(other) --> bool --> 判斷當前集合是否是另一個集合的子集
--> 使用 <= 表示
set1 < set2 : 判斷set1是否是set2的真子集
s.isssuperset(other) --> bool --> 判斷當前集合是否是other的超集
--> 使用 >= 表示
set1 > set2 : 判斷set1是否是other的真超集
s.isdisjoint(other) --> bool --> 判斷當前集合和另一個集合有沒有交集
5-python的封裝與結構 - set集合