解構與封裝
解構
什麼是結構?如下講兩個例子
解構:按照元素順序, 把線性結構的元素賦值給變量。
簡單一點的例子
In [26]: x = 1
In [27]: y = 2
In [28]: tmp = x
In [29]: x = y
In [30]: y = tmp
In [31]: print(x, y)
2 1
複雜一點的例子
In [32]: x, y = y, x
In [33]: print(x, y)
1 2
In [36]: lst = [1, 2]
In [37]: first = lst[0]
In [38]: second = lst[1]
In [39]: first, second = lst # 解構
In [40]: print(first, second)
1 2
封裝
- 定義一個元組, 可以省略小括號
- 封裝出來的一定是元組
In [43]: t = 1, 2
In [44]: t
Out[44]: (1, 2)
In [45]: type(t)
Out[45]: tuple
定義一個元組, 可以省略小括號
In [46]: t1 = (1, 2)
In [47]: t2 = 1, 2
t1和t2的效果是相等的。
封裝出來的一定是元組
python3與python2解構不同之處
上述就是Python2和Python3解構的相同之處,Python3還帶來一些新的解構變化
總結:
- 不加*號的解構
- 元素按照順序賦值給變量。
- 變量和元素必須匹配。
- 加*號的解構
- 加星號變量, 可以接收任意個數的元素。
- 加星號的變量不能單獨出現。在一個表達式也只能出現1次
- *號位置可以在表達式中任意地方出現。(左中右)
加*號的場景
依然用實例說話
場景1:*號參數位於中間
In [48]: lst = list(range(1000))
In [49]: head, *mid, tail = lst
In [50]: head
Out[50]: 0
In [51]: tail
Out[51]: 999
In [52]: mid
Out[52]:
[1,
2,
...
...
998]
In [67]: first, sceond, *other, last = lst # 這種情況也是允許的
In [68]: first
Out[68]: 0
In [69]: sceond
Out[69]: 1
In [70]: other
Out[70]: [2, 3]
In [71]: last
Out[71]: 4
場景2:*號位於最右邊
In [53]: lst = list(range(5))
In [54]: head, *tail = lst
In [55]: head
Out[55]: 0
In [56]: tail
Out[56]: [1, 2, 3, 4]
In [63]: first, sceond, *other = lst # 這種情況下是允許的
In [64]: first
Out[64]: 0
In [65]: sceond
Out[65]: 1
In [66]: other
Out[66]: [2, 3, 4]
場景3:只有一個星號, 沒有其他參數
In [58]: *lst2 = lst # 左邊只有一個加星號的變量是不行的
File "<ipython-input-58-98211a44ccfb>", line 1
*lst2 = lst
^
SyntaxError: starred assignment target must be in a list or tuple
場景4:星號位於最左邊
In [59]: *head, tail = lst # 這種是OK的
In [60]: head
Out[60]: [0, 1, 2, 3]
In [61]: tail
Out[61]: 4
場景5:多個星號
In [62]: head, *m1, *m2, tail = lst # 兩個*號是不行的
File "<ipython-input-62-1fc1a52caa8e>", line 1
head, *m1, *m2, tail = lst
^
SyntaxError: two starred expressions in assignment
左右有多個加星號的變量也是不行的。
不加*號場景
場景1:左邊變量數超過右邊元素個數的時候
In [72]: v1, v2, v3, v4, v5, v6, v7 = lst # 左邊變量數超過右邊元素個數的時候, 是不行。
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-72-9366cfb498a1> in <module>()
----> 1 v1, v2, v3, v4, v5, v6, v7 = lst
ValueError: not enough values to unpack (expected 7, got 5)
場景2:左邊變量數小於右邊元素個數
In [73]: v1, v2 = lst # 左邊變量數小於右邊元素個數, 且左邊沒有加星號的變量
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-73-d7b0a4e7871e> in <module>()
----> 1 v1, v2 = lst
ValueError: too many values to unpack (expected 2)
解構返回的都是列表
In [83]: f, *t = (1, 2, 3, 4)
In [84]: t # 返回的都是一個列表
Out[84]: [2, 3, 4]
_下劃線在解構中的作用
python的一個慣例, 使用單個下劃線_表示丟棄該變量。
In [85]: head, *_, tial = lst
In [86]: head
Out[86]: 0
In [87]: tail
Out[87]: 4
In [88]: _ # python的一個慣例, 使用單個下劃線_表示丟棄該變量。
Out[88]: 4
單個下劃線也是python合法的標識符, 但是如果不是要丟棄一個變量, 通常不要用單個下劃線表示一個有意義的變量。
在gettext, 多語言gettext('bbbb'), 通常會重命名_ _('dfasfdasd')
在gettext中的慣例, 會覆蓋python中_丟棄的變量。
In [2]: head, *_ = 'I love Python'
In [3]: head
Out[3]: 'I'
In [4]: _
Out[4]: 'I'
ipython把返回值臨時保存在_
In [5]: [1, 2, 3, 4]
Out[5]: [1, 2, 3, 4]
In [6]: _
Out[6]: [1, 2, 3, 4]
多層次的解構
解構也可以用在多層次(比如一個列表中還有一個元組)的語句上。
非常複雜的數據結構, 多層嵌套的線性結構的時候, 可以用結構快速提取其中的值。
解構用的多的地方在於函數的返回值, 函數返回值封裝一個元組
In [11]: lst = [1, (2, 3), 5]
In [12]: _, v, *_ = lst
In [13]: _, val = v # 複雜的實現
In [15]: val
Out[15]: 3
In [16]: _, (_, val), *_ = lst # 直接的實現
In [17]: val
Out[17]: 3
解構是支持多層次的
In [25]: lst
Out[25]: [0, (1, 2), 2, 3, 4, 5, 6, 7, 8, 9]
In [26]: _, (*_, tail), *_ = lst
In [27]: tail
Out[27]: 2
In [28]: _, [*_, tail], *_ = lst # 可以以列表的形式
In [29]: tail
Out[29]: 2
非常複雜的數據結構, 多層嵌套的線性結構的時候, 可以用結構快速提取其中的值。
解構用的多的地方在於函數的返回值, 函數返回值封裝一個元組
In [33]: key, _, value = 'env = prod'.partition('=') # 快速匹配key, value
In [34]: key
Out[34]: 'env '
In [35]: value
Out[35]: ' prod'
沒有解構, 我們也可以活下來, 但是有了結構, 生活很美好
解構這個特性, 被很多的語言借鑑。