結合 list()
與 range()
可以快速產生連續元素的列表:
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
也可以在 range()
裡面指定進階參數:
>>> list(range(7, 23, 3))
[7, 10, 13, 16, 19, 22]
如果要取得列表的第一個元素,可以指定 arr[0]
,那如果要取得最後幾個元素呢?可以使用負數索引值:
>>> arr = list(range(10))
>>> arr[0], arr[1], arr[-1], arr[-2]
(0, 1, 9, 8)
arr[-1]
就是倒數第一個元素,arr[-2]
就是倒數第二個元素。
當我們想要從列表中取出一份子列表時,可以利用切片 (Slice) 語法:
>>> arr = list(range(10))
>>> arr[3:7]
[3, 4, 5, 6]
arr[3:7]
代表從索引值為 3 的元素開始,一路取到索引值 7 之前,但是不包含 7,因此取出了 3, 4, 5, 6 等四個元素。也可以跳著取:
>>> arr[2:8:2]
[2, 4, 6]
arr[2:8:2]
代表從索引值 2 開始取到索引值 8 之前,並且每 2 個取一次,因此 3, 5, 7 被跳過,只留下 2, 4, 6 等。
第一個數字跟第二個數字可以留白,如果沒有指定第一個數字,代表從開頭開始取;如果沒有指定第二個數字,代表取到列表的結尾:
>>> print(arr[:7]) # 取到 7 之前
>>> print(arr[3:]) # 從 3 開始取
>>> print(arr[::]) # 都不給,純炫技?
[0, 1, 2, 3, 4, 5, 6]
[3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
兩個都不給的話,就是原本的列表,乍看之下好像純為炫技?其實不然,當我們將列表直接指定給其他變數時,彼此之間的修改會互相影響:
>>> arr1 = list(range(10))
>>> arr2 = arr1
>>> arr2[1] = -1
>>> print(arr1)
>>> print(arr2)
[0, -1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, -1, 2, 3, 4, 5, 6, 7, 8, 9]
一開始將 arr1
指定給 arr2
,當 arr2
被修改時,連 arr1
也一同被修改掉。這其實與一般的整數變數行為並不相同:
>>> a = 5
>>> b = a
>>> b += 1
>>> a, b
(5, 6)
可以看到,一樣是把 a
指定給 b
,但是修改 b
變數並不會導致 a
也被修改。這是因為列表屬於可變的 (Mutable) 物件,而整數屬於不可變的 (Immutable) 的資料。
所謂的可變與不可變指的是變數的內容在記憶體裡面的狀態。當一個列表被紀錄在記憶裡面時,他的內容、長度都是可以修改的,因此被稱為可變的。而整數看起來似乎也能修改,但其實變數
b
從 5 變成 6 的過程中,是b
變成了 6,而不是 5 變成 6,系統會創造一個新的整數放到b
裡面,所以整數、浮點數等被稱為不可變的。
物件為可變或不可變的性質,對其參數傳遞、賦值複製等行為有很大的影響。因為可變的物件通常很大,一個列表可能有成千上萬個數值,若是每次都複製成不同列表,會對記憶體造成很大的負擔,因此預設是不複製列表的,而是讓變數們都指向同一塊記憶體。當我們想要複製列表時,就可以透過切片的技巧來達成:
>>> arr1 = list(range(10))
>>> arr2 = arr1[::]
>>> arr2[1] = -1
>>> print(arr1)
>>> print(arr2)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, -1, 2, 3, 4, 5, 6, 7, 8, 9]
這樣修改 arr2
時,就不會影響到 arr1
了。其實可以直接用一個冒號 arr1[:]
就好,寫兩個冒號只是我的習慣 🤣
切片除了能放在賦值右邊,也能放在賦值左邊:
>>> arr1 = list(range(10))
>>> print(arr1)
>>>
>>> arr1[5:] = [10, 20, 30, 40, 50]
>>> print(arr1)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 10, 20, 30, 40, 50]
odd_pow()
傳入一個列表,將索引值為奇數的元素挑出來,計算他的平方再回傳。完整的程式碼放在此 Colab 裡面供各位參考。