從 JavaScript 角度學 Python(10) - 容器型別(下)

前言

前一篇我們聊了一些字典有趣的取值方式,所以接下來我想接著繼續聊關於字典的部分。

字典取值

在 JavaScript 中我們時常會使用到兩個很好用的 ES6 語法取出物件屬性名稱與物件屬性值,沒有錯,就是 Object.keys()Object.values(),而這兩個語法都有異曲同工之處,底層實作會將物件中的屬性名稱與值使用 for...in 全部跑過一次並回傳其結果,而回傳的結果會是一個陣列。

Object.keys() 來講就是回傳物件的屬性:

1
2
3
4
5
6
7
8
9
10
var obj = {
myName: 'Ray',
a: '1',
b: '2',
fn() {
console.log('123')
}
};

console.log(Object.keys(obj)); // [ "myName", "a", "b", "fn" ]

Object.values() 則是回傳屬性的值:

1
2
3
4
5
6
7
8
9
10
var obj = {
myName: 'Ray',
a: '1',
b: '2',
fn() {
console.log('123')
}
};

console.log(Object.values(obj)); // [ "Ray", "1", "2", fn() ]

可以看到如果是函式的話,就會直接回傳你一個函式。

那麼 Python 也有相同的功能嗎?有的,一樣也是叫做 keysvalues

1
2
3
4
5
6
7
8
dis = {
'myName': 'Ray',
'a': '1',
'b': '2',
}

print(dis.keys()) # dict_keys(['myName', 'a', 'b'])
print(dis.values()) # dict_values(['Ray', '1', '2'])

看到 dict_keysdict_values,不用太害怕,它只是告訴你這是字典的 keysvalues 而已。

但是這邊要注意,如果你直接使用 dis.keys()[0] 取值是會出現錯誤的:

1
2
3
4
5
6
7
dis = {
'myName': 'Ray',
'a': '1',
'b': '2',
}

print(dis.keys()[0]) # TypeError: 'dict_keys' object is not subscriptable

有沒有覺得自己好像被陰了一下?

我腦袋好混亂啊

畢竟我們在 JavaScript 中使用 Object.keys()Object.values() 之後就可以直接執行一些陣列操作方法,但是在 Python 是必須額外處理的,因此你必須使用 list() 將它轉換成串列,這樣子才能夠正確的取值:

1
2
3
4
5
6
7
8
dis = {
'myName': 'Ray',
'a': '1',
'b': '2',
}

print(list(dis.keys())[0]) # myName
print(list(dis.values())[0]) # Ray

最後一個則是 Python 的 items 方法,而 items 與 JavaScript 的 Object.entries 非常雷同,會將屬性與值一起都回傳出來:

1
2
3
4
5
6
7
var obj = {
myName: 'Ray',
a: '1',
b: '2',
};

console.log(Object.entries(obj)); // [ [ "myName", "Ray" ], [ "a", "1" ], [ "b", "2" ] ]

但是在講 items 方法之前,先讓我跳來講另一個前面沒有講到的東西東西也就是 **元組(Tuple)**。

元組(Tuple)

元組很特別,它是一個類似串列的容器,看到這邊可能有些寫過 TypeScript 的人會很興奮,畢竟 TypeScript 中也有一個叫做元組的型別:

1
2
3
const a: [string, number];
a = ['Ray', 1];
console.log(a[0]); // Ray

我好興奮啊

但是在 Python 的元組宣告方式是使用括號 () 來宣告,除此之外它還有一個特性,元組是 read only (唯讀) 的,當你宣告了這個元組之後你就無法再更改它,但取值的方式與串列沒有差異:

1
2
tpe = (1, 2, 3)
print(tpe[0]) # 1

只要你做出了修改值的行為就會出現錯誤:

1
2
3
tpe = (1, 2, 3)
tpe[0] = 10 # TypeError: 'tuple' object does not support item assignment
print(tpe[0])

所以如果你有需要修改的需求,那麼還是會建議你使用串列就好:

1
2
3
tpe = [1, 2, 3]
tpe[0] = 10
print(tpe) # [10, 2, 3]

回到 items 的部分,為什麼要先講元組呢?因為使用 items 取出來的字典會是一個元組:

1
2
3
4
5
6
7
dis = {
'myName': 'Ray',
'a': '1',
'b': '2',
}

print(list(dis.items())) # [('myName', 'Ray'), ('a', '1'), ('b', '2')]

這就是為什麼要先拉過來介紹元組了,因為使用 items 取出來的串列都會是唯讀不可修改:

1
2
3
4
5
6
7
8
9
10
dis = {
'myName': 'Ray',
'a': '1',
'b': '2',
}
print(list(dis.items())) # [('myName', 'Ray'), ('a', '1'), ('b', '2')]
print(list(dis.items())[0]) # ('myName', 'Ray')
print(list(dis.items())[0][1]) # 'Ray'

list(dis.items())[0][1] = 'Ray2' # TypeError: 'tuple' object does not support item assignment

元組中的字典

雖然我們前面有說明到元祖本身是 read only (唯讀):

1
2
tup = (1, 2, 3)
tup[0] = 1 # TypeError: 'tuple' object does not support item assignment

可是如果今天修改的是元組內的字典屬性可以不可以呢?答案基本上是可以的:

1
2
3
4
5
6
tup = ({
'myName1': 'Ray1'
},{
'myName2': 'Ray2'
})
tup[0]['myName1'] = 'QQ'

那麼這是為什麼?主要原因是我們是修改的字典中的屬性,並不是修改本身元組所指向的字典記憶點位置,因此就可以修改字典的值,甚至是新增另一個屬性也可以:

1
2
3
4
5
6
7
tup = ({
'myName1': 'Ray1'
},{
'myName2': 'Ray2'
})
tup[0]['myName1'] = 'QQ'
tup[0]['blog'] = 'Welcome.Web.World - Ray Blog'

除非你今天是重新指向給它新的字典位置才會出現錯誤:

1
2
3
4
5
6
7
8
tup = ({
'myName1': 'Ray1'
},{
'myName2': 'Ray2'
})
tup[0]['myName1'] = 'QQ'
tup[0]['blog'] = 'Welcome.Web.World - Ray Blog'
tup[0] = {} # TypeError: 'tuple' object does not support item assignment

而這邊的概念就 JavaScript 中的 const obj = {}; 的概念是非常雷同的唷。

in 運算子

最後額外補充聊一下 in 運算子,基本上這個運算子的概念就如同 JavaScript 的 Object.hasOwnProperty 方法,hasOwnProperty 可以用於尋找該屬性是否存在於這個物件中:

1
2
3
4
var obj = {
myName: 'Ray',
}
obj.hasOwnProperty('myName'); // true

而 Python 中的 in 運算子也是一樣的存在,如果存在就會回傳 True,如果不存在就是 False,但是這個運算子的寫法是屬性在前,字典在後:

1
2
3
4
5
6
7
dis = {
'myName': 'Ray',
'a': '1',
'b': '2',
}

print('myName' in dis) # True

透過閱讀程式碼就可以很明確的知道這一段正在表達「字串 myName 在不在 dis 字典中。」這一段話。

題外話,其實 JavaScript 也有 in 運算子,只是我自己很少使用:

1
2
3
4
5
var obj = {
myName: 'Ray',
}

console.log('myName' in obj); // true

作者的話

這幾天算是把花雕酒給消耗完畢了,但是跑去逛全聯時卻一個腦弱不小心又敗了一瓶紹興酒回來…看來又要開始製作醉雞之路了…

關於兔兔們

兔法無邊

Liker 讚賞 (拍手)

如果這一篇筆記文章對你有幫助,希望可以求點支持或 牡蠣 鼓勵 (ノД`)・゜・。

Liker 是一個按讚(拍手)的讚賞機制,每一篇文章最多可以按五下(拍手),按讚過程你是完全不用付費的(除非你想要每個月贊助我 :D),你只需要登入帳號就可以開始按讚。
而 Liker 會依據按讚數量分配獎金給創作者,所以如果你願意按個讚我會非常感謝你唷。

Google AD

撰寫一篇文章其實真的很花時間,如果你願意「關閉 Adblock (廣告阻擋器)」來支持我的話,我會非常感謝你 ヽ(・∀・)ノ