iT邦幫忙

2021 iThome 鐵人賽

DAY 9
2
Software Development

從 JavaScript 角度學 Python系列 第 9

從 JavaScript 角度學 Python(9) - 容器型別(上)

前言

BMI 作業做得還好嗎?不知道你有沒有完成,但是這邊時間不等人,所以我們就接著聊聊下一個主題吧。

什麼是容器型別?

接下要聊聊的是 Python 另一種型別,也就是容器型別。

其實在 JavaScript 中這個型別就是所謂的物件型別,只是在 Python 則是稱為容器型別。

那...什麼是容器型別呢?容器型別你可以把它想像成類似使用一個個的馬克杯或者是盒子,可以用來放各種東西,就如同前面所言以 JavaScript 來講的容器型別就是陣列與物件:

// 陣列 Array
var arr = ['Ray'];

// 物件 Object
var obj = {
  name: 'Ray',
};

(這邊要注意陣列依然是屬於物件型別,原因可詳見:JavaScript 核心觀念(31)-物件-陣列)

那麼在 Python 上並不稱為陣列與物件,而是串列(List) 與字典 (Dictionaries):

  • Array(陣列) === List(串列)
  • Object(物件) === Dictionaries(字典)

那麼寫法會不會有差異呢?基本上串列是沒有什麼太大的差異,但是在字典上就會有一點差異:

# 串列
lis = ['Ray']

# 字典
dic = {
  'name': 'Ray',
}

為什麼會說字典有一點差異呢?先讓我們轉過來看一下 JavaScript 的部分,在 JavaScript 的物件屬性我們是可以省略單/雙引號的:

var obj = {
  name: 'Ray',
};

但是在 Python 是不能省略這個單/雙引號的,否則你是會出現 NameError: name 'name' is not defined 的唷~

https://ithelp.ithome.com.tw/upload/images/20210909/20119486WBfAJQlemP.png

那麼由於這個錯誤訊息的關係,代表著沒有使用單/雙引號包覆的這個屬性,是會被 Python 認為這是 一個變數

因此我們可以大膽的嘗試與挑戰一件事情,假使我宣告了一個變數並且字典的屬性不用使用單/雙引號包覆,其結果又會如何呢?

name = 'myName'

dic = {
  name: 'Ray',
}

print(dic) # ??

我們可以看到結果是可以正常運作的:

https://ithelp.ithome.com.tw/upload/images/20210909/20119486l97Q6Ef5ea.png

是不是發現與我們原本的 JavaScript 有些許不同呢?在一般的情況下 JavaScript 是不允許你將物件的屬性變成變數傳入的,不管怎樣都會被 JavaScript 轉換成一個字串屬性,只是在呈現與撰寫上它會忽略並允許你這樣做而已:

var name = 'myName';

var obj = {
  name: 'Ray',
};

console.log(obj); // { name: "Ray" }

但是如果真的有這種例外狀況,也就是物件的屬性是必須透過變數所傳入的話,其實也可以做到,這時候你所必須使用是中括號運算子來達到這個需求:

var name = 'myName';

var obj = {
  [name]: 'Ray',
};

console.log(obj); // { myName: "Ray" }

See!效果基本上是一樣的,只是變成另一種呈現方式罷了。

容器型別取值

接下來就是容器取值,串列取值與字典取值的部分會與原本的 JavaScript 也有差別嗎?先讓我們回顧看一下在 JavaScript 中物件取值與陣列取值的方式:

// 陣列取值
var arr = ['Ray'];
arr[0]; // Ray

var obj = {
  name: 'Ray',
};
// 點運算子取值
obj.name; // Ray
// 中括號運算子取值
obj['name'];

// 中括號運算子 + 變數取值
var variable = 'name';
obj[variable]; // Ray

基本上在 JavaScript 中取值的行為主要有兩種方式:

  • 點運算子 - .
  • 中括號運算子 - []

那麼在 Python 中也是相同的嗎?如果是的話,那麼應該如何撰寫呢?讓我們看一下範例:

# 字串取值
lis = ['Ray']
lis[0] # 'Ray'

dic = {
  'name': 'Ray',
}

dis['name'] # 'Ray'
variable = 'name'
dic[variable] # 'Ray'

你可以發現上面範例我並沒有使用點運算子來取值,原因是因為 Python 無法像 JavaScript 一樣使用點運算子的方式取值,但是 Python 有一些滿特別且好玩的函式方法可以取值,例如 get()

dic = {
  'name': 'Ray',
}

dic.get('name', 'N/A') # 'Ray'

那這個 get() 語法有何用途呢?主要可以傳入兩個參數,第一個參數是你預計要取值的屬性名稱,第二個則是如果沒有這個屬性名稱存在時要回傳什麼東西給你,舉例來講:

dic = {
  'name': 'Ray',
}

dic.get('qq', 'no key') # 'no key'

我們可以發現這種取值方式可以避免當字典的屬性不存在時的錯誤,而且可以客製化錯誤訊息,是不是相當棒呢?

等等,這邊好像一直都沒有提到字典屬性不存在會發生什麼事情對吧?JavaScript 中若我們取一個不存在的物件屬性時,會出現 undefined,並且還可以繼續執行:

var obj = {};

console.log(obj.myName); // undefined
console.log('我執行囉');

但是在 Python 中則會直接中斷程式碼出現 'KeyError: xxx' 的錯誤訊息:

name = 'myName'

dic = {
  name: 'Ray',
}

print(dic[name])
print(dic['qq'])
print('我不能執行了')

https://ithelp.ithome.com.tw/upload/images/20210909/201194867FX5YCtzNq.png

好吧,這時候你可能壓力大了,難不成我每次都要先寫好屬性名稱嗎?

https://ithelp.ithome.com.tw/upload/images/20210909/201194864yBTyPtNi4.png

難道沒有一種方式是「當這個值不存在時,就寫入一個預設屬性與值」的方式嗎?

答案是有的!

這時候就要使用 setdefault() 這個函式方法,主要也是兩個參數,第一個參數是要設定/取得的屬性名稱,第二個參數則是如果這個屬性不存在時,要預設寫入的值。

舉例來講,假使今天這個屬性不存在時,必須出現「這是一段話」:

name = 'myName'

dic = {
  name: 'Ray',
}

print(dic[name])
print(dic.setdefault('qq', '這是一段話'))
print('我不能執行了')

https://ithelp.ithome.com.tw/upload/images/20210909/20119486NDaqRAYtWi.png

反之,如果這個屬性已經存在於字典中,那麼它就會走原本本身的值,而不會被覆蓋:

name = 'myName'

dic = {
  name: 'Ray',
  'qq': '我已經存在囉'
}

print(dic[name])
print(dic.setdefault('qq', '這是一段話'))
print('我不能執行了')

https://ithelp.ithome.com.tw/upload/images/20210909/20119486DrsgYSIOQ2.png

掌握 setdefault 之後你也可以用這個方式去針對 qq 增加一個字典,也就是巢狀物件的概念:

name = 'myName'

dic = {
  name: 'Ray',
}

print(dic[name])
print(dic.setdefault('qq', {}))
print(dic['qq'].setdefault('sayHi', 'Hello Ray')) # 也可以寫成 dic.setdefault('qq', {}).setdefault('sayHi', 'Hello Ray')
print('我不能執行了')

相信你已經深深了解到 get()setdefault() 兩者美妙之處,那該選擇哪一個使用就留給你思考囉~

https://ithelp.ithome.com.tw/upload/images/20210909/201194863q7pszlvQW.png

作者的話

有朋友問我的花雕醉雞卷是如何製作的,所以就順便分享一下材料,基本上就是 200cc 花雕酒、100cc 米酒(我是天味米酒,你可以考慮紅標米酒)、適量的白胡椒就這麼簡單的材料而已,如果你想加入當歸那些也是可以。

關於兔兔們

兔法無邊


上一篇
從 JavaScript 角度學 Python(8) - BMI 計算(1)
下一篇
從 JavaScript 角度學 Python(10) - 容器型別(下)
系列文
從 JavaScript 角度學 Python31

尚未有邦友留言

立即登入留言