5-python的封裝與結構 - set集合

1 封裝與解構

        封裝與解構屬於Python語言的一種特性,它使用起來很像其餘語言中的"逗號表達式",但內部原理是不一樣的,在某些場景下:好比變量交換複製時使用,顯得很是優雅。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

須要注意的是:code

  1. *變量名,這種格式不能單獨使用
  2. 也不能多個*變量名,連續使用(由於從原理上看,兩個、*變量名連起來使用,會引發歧義,因此Python禁止了這種寫法)
  3. *_這種格式,能夠收集足夠多的元素丟棄
# 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不支持索引切片或者其餘的類序列的操做。ip

    什麼是可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提供了兩種定義一個集合的方式,addupdate,他們的用法以下:

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是容器,那麼咱們就能夠對容器內的元素進行判斷,那麼就須要使用成員判斷符 innot 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 --> 判斷當前集合和另外一個集合有沒有交集
相關文章
相關標籤/搜索