iT邦幫忙

2021 iThome 鐵人賽

DAY 10
1
Software Development

從 JavaScript 角度學 Python系列 第 10

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

前言

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

字典取值

在 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 也有相同的功能嗎?有的,一樣也是叫做 keysvalues

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] 取值是會出現錯誤的:

dis = {
  'myName': 'Ray',
  'a': '1',
  'b': '2',
}

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

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

https://ithelp.ithome.com.tw/upload/images/20210910/20119486BXK0qV21aG.png

畢竟我們在 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)

元組(Tuple)

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

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

https://ithelp.ithome.com.tw/upload/images/20210910/20119486ryluI6cphm.png

但是在 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 運算子

最後額外補充聊一下 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

作者的話

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

關於兔兔們

兔法無邊


上一篇
從 JavaScript 角度學 Python(9) - 容器型別(上)
下一篇
從 JavaScript 角度學 Python(11) - 串列 20 種操作的方法
系列文
從 JavaScript 角度學 Python31

尚未有邦友留言

立即登入留言