前一篇我們聊了一些字典有趣的取值方式,所以接下來我想接著繼續聊關於字典的部分。
在 JavaScript 中我們時常會使用到兩個很好用的 ES6 語法取出物件屬性名稱與物件屬性值,沒有錯,就是 Object.keys()
、Object.values()
,而這兩個語法都有異曲同工之處,底層實作會將物件中的屬性名稱與值使用 for...in
全部跑過一次並回傳其結果,而回傳的結果會是一個陣列。
以 Object.keys()
來講就是回傳物件的屬性:
var obj = {
myName: 'Ray',
a: '1',
b: '2',
fn() {
console.log('123')
}
};
console.log(Object.keys(obj)); // [ "myName", "a", "b", "fn" ]
而 Object.values()
則是回傳屬性的值:
var obj = {
myName: 'Ray',
a: '1',
b: '2',
fn() {
console.log('123')
}
};
console.log(Object.values(obj)); // [ "Ray", "1", "2", fn() ]
可以看到如果是函式的話,就會直接回傳你一個函式。
那麼 Python 也有相同的功能嗎?有的,一樣也是叫做 keys
、values
:
dis = {
'myName': 'Ray',
'a': '1',
'b': '2',
}
print(dis.keys()) # dict_keys(['myName', 'a', 'b'])
print(dis.values()) # dict_values(['Ray', '1', '2'])
看到 dict_keys
、dict_values
,不用太害怕,它只是告訴你這是字典的 keys
與 values
而已。
但是這邊要注意,如果你直接使用 dis.keys()[0]
取值是會出現錯誤的:
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()
將它轉換成串列,這樣子才能夠正確的取值:
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
非常雷同,會將屬性與值一起都回傳出來:
var obj = {
myName: 'Ray',
a: '1',
b: '2',
};
console.log(Object.entries(obj)); // [ [ "myName", "Ray" ], [ "a", "1" ], [ "b", "2" ] ]
但是在講 items
方法之前,先讓我跳來講另一個前面沒有講到的東西東西也就是 元組(Tuple)。
元組很特別,它是一個類似串列的容器,看到這邊可能有些寫過 TypeScript 的人會很興奮,畢竟 TypeScript 中也有一個叫做元組的型別:
const a: [string, number];
a = ['Ray', 1];
console.log(a[0]); // Ray
但是在 Python 的元組宣告方式是使用括號 ()
來宣告,除此之外它還有一個特性,元組是 read only (唯讀) 的,當你宣告了這個元組之後你就無法再更改它,但取值的方式與串列沒有差異:
tpe = (1, 2, 3)
print(tpe[0]) # 1
只要你做出了修改值的行為就會出現錯誤:
tpe = (1, 2, 3)
tpe[0] = 10 # TypeError: 'tuple' object does not support item assignment
print(tpe[0])
所以如果你有需要修改的需求,那麼還是會建議你使用串列就好:
tpe = [1, 2, 3]
tpe[0] = 10
print(tpe) # [10, 2, 3]
回到 items
的部分,為什麼要先講元組呢?因為使用 items
取出來的字典會是一個元組:
dis = {
'myName': 'Ray',
'a': '1',
'b': '2',
}
print(list(dis.items())) # [('myName', 'Ray'), ('a', '1'), ('b', '2')]
這就是為什麼要先拉過來介紹元組了,因為使用 items
取出來的串列都會是唯讀不可修改:
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 (唯讀):
tup = (1, 2, 3)
tup[0] = 1 # TypeError: 'tuple' object does not support item assignment
可是如果今天修改的是元組內的字典屬性可以不可以呢?答案基本上是可以的:
tup = ({
'myName1': 'Ray1'
},{
'myName2': 'Ray2'
})
tup[0]['myName1'] = 'QQ'
那麼這是為什麼?主要原因是我們是修改的字典中的屬性,並不是修改本身元組所指向的字典記憶點位置,因此就可以修改字典的值,甚至是新增另一個屬性也可以:
tup = ({
'myName1': 'Ray1'
},{
'myName2': 'Ray2'
})
tup[0]['myName1'] = 'QQ'
tup[0]['blog'] = 'Welcome.Web.World - Ray Blog'
除非你今天是重新指向給它新的字典位置才會出現錯誤:
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
運算子,基本上這個運算子的概念就如同 JavaScript 的 Object.hasOwnProperty
方法,hasOwnProperty
可以用於尋找該屬性是否存在於這個物件中:
var obj = {
myName: 'Ray',
}
obj.hasOwnProperty('myName'); // true
而 Python 中的 in
運算子也是一樣的存在,如果存在就會回傳 True
,如果不存在就是 False
,但是這個運算子的寫法是屬性在前,字典在後:
dis = {
'myName': 'Ray',
'a': '1',
'b': '2',
}
print('myName' in dis) # True
透過閱讀程式碼就可以很明確的知道這一段正在表達「字串 myName
在不在 dis
字典中。」這一段話。
題外話,其實 JavaScript 也有 in
運算子,只是我自己很少使用:
var obj = {
myName: 'Ray',
}
console.log('myName' in obj); // true
這幾天算是把花雕酒給消耗完畢了,但是跑去逛全聯時卻一個腦弱不小心又敗了一瓶紹興酒回來...看來又要開始製作醉雞之路了...