การทำงานกับ Dictionary ใน Python
Dictionary จะเหมือนกับ JSON ใน Javascript ซึ่งจะ map ระหว่าง key และ value บางครี้งอาจ เรียกว่า maps หรือ associative array
current_movies = {} # ประกาศ empty dict
current_movies = {'equalizer 3': '11:00am',
'john wick 4': '1:00pm',
'batman': '3:00pm'}
print(current_movies['equalizer 3'])
# ผลลัพธ์ที่ได้จะเป็นแบบนี้
{'equalizer 3': '11:00am', 'john wick 4': '1:00pm', 'batman': '3:00pm'}
นอกจากการประกาศในรูปแบบด้านบนแล้วเรายังสามารถใช้ dict constructor แบบนี้ก็ได้
current_movies = dict(equalizer = '11:00am', johnwick = '1:00pm', batman = '3:00pm')
ซึ่งจะได้ผลลัพธ์แบบเดียวกับตัวอย่างก่อนหน้า แต่ key จะมีเว้นวรรคหรืออักขระพิเศษไม่ได้
ตั้งแต่ python 3.7 เป็นต้นไป dict จะเปลี่ยนเป็นตัวแปรที่มีการเรียงลำดับ(ordered)
การ get ค่าจาก dict
showtime = current_movies.get('equalizer 3')
แนะนำว่า key ที่เราใช้ควรจะเป็นตัวพิมพิ์เล็ก(lowercase) เวลารับ input เข้ามาจะได้พิมพิ์ได้ทั้งตัวพิมพิ์ใหญ่(uppercase) และตัวพิมพิ์เล็ก(lowercase) แบบนี้
movie = input('What movie would you like the showtime for?\n')
showtime = current_movies.get(movie.lower())
และถ้าเกิดเราพิมพิ์ชื่อหนังที่ไม่มีอยู่ใน dict python จะ return None ออกมาให้ เราเลยต้องทำการ handle ค่า None ด้วยเงื่อนไข ดังนี้
if(showtime is None):
print("Requested movie isn't playing")
else:
print(movie, 'is playing at', showtime)
เราควรต้องใช้ is เพราะจะเฉพาะ None เท่านั้นถึงจะเป็น True(Explicit)
ตามหลักการของ Zen of Python Explicit better than implicit
การวน loop เพื่อเข้าถึงสมาชิกใน dict
เราสามารถดึงออกมาเฉพาะ key แบบนี้ก็ได้
for key in current_movies:
print(key, current_movies[key])
หรือถ้าต้องการใช้ทั้ง key และ value ให้เรียกใช้ items() method แบบนี้ code จะอ่านง่ายขึ้นกว่าตัวอย่างก่อนหน้ามากๆ
for key, value in current_movies.items():
print(key, value)
Dict to JSON
การเพิ่มสมาชิกใหม่เข้ามาใน dict
# add สมาชิกใหม่เข้าไปได้เลย
current_movies['expand4ble'] = '10:00pm'
หรือจะใช้ update method แบบนี้ก็ได้
current_movies.update({'expand4ble': '10:00pm'})
ถ้าเราใส่ key ที่มีอยู่แล้ว python จะนำข้อมูลไป update value ของ key ที่มีอยู่แล้ว เช่น
current_movies['batman'] = '1:00am'
# หรือ
current_movies.update({'batman': '1:00am'})
# ผลลัพธ์จะออกมาเป็นแบบนี้
{ 'equalizer 3': '11:00am',
'john wick 4': '1:00pm',
'batman': '1:00am'
}
การลบสมาชิกใน dictionary ออก
เราสสามารถนำข้อมูลออกจาก dict ได้เหมือนกับ list แบบนี้
del current_movies['expand4ble']
หรืออาจเลือกใช้ pop() method แบบนี้ก็ได้
current_movies.pop('expand4ble')
นอกจาก pop() method เรายังมี popitem() method ที่จะ pop เอา สมาชิกตัวสุดท้ายออก
current_movies.popitem()
ใน python version ที่เก่ากว่า 3.7 python จะยังไม่รู้ว่าตัวไหนมาหลังสุด เนื่องจากยังเป็น unordered ดังนั้นถ้าเรา popitem() จะเป็นการ random สมาชิกออกมา 1 ตัว
ถ้าในกรณีที่เราใส่ key ที่ไม่มีอยู่ใน dict
del current_movies['xxx']
# หรือ
current_movies.pop('xxx')
ก็จะเกิด KeyError แบบนี้
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'xxx'
และในกรณีที่เราต้องการลบสมาชิกทุกตัวใน dict เราจะใช้ clear() method
current_movies.clear()
การลบ dictionary
เราสามารถลบ dict ทั้งตัวได้เลย ด้วยการใช้ del เหมือนกับที่เราใช้ลบสมาชิกใน dict ออก
del current_movies
ข้อควรระวัง ถ้าเราลืมใส่ key เข้าไปจะทำให้ dict นั้นหายไปทั้งตัวเลย
การ Copy dict
ทำไมเราต้อง copy เราแต่ assign ตัวแปร dict ให้กับตัวแปรอื่นก็ได้ไม่ใช่เหรอ
dict1 = {a: 10, b: 20}
dict2 = dict1
ถ้าเราทำแบบนี้คุณต้องเข้าใจว่าการเปลี่ยนแปลงใน dict1 หรือ dict2 จะกระทบกับอีกตัวทันที เพราะทั้ง 2 ตัวแปรนี้ชี้ไปที่เดียวกัน
dict1.update({c: 30})
print(dict2)
# ผลลัพธ์จะออกมาเป็น
{'a': '10', 'b': '20', 'c': 30}
เราแก้ dict1 แต่ dict2 เกิดการเปลี่ยนแปลงตามไปด้วย เพราะทั้ง 2 ตัวแปรนี้ชี้ไปที่เดียวกัน
ดังนั้นถ้าเราอยากได้ dict ตัวใหม่ที่ไม่เกี่ยวข้องกับตัวเดิมเราจะใช้ การ copy ซึ่งจะมีอยู่ 2 วิธีด้วยกัน คือ
-
ใช้ copy() method
dict2 = dict1.copy()
-
ใช้ dict constructor
dict2 = dict(dict1)
หลังจากนี้ dict1 และ dict2 จะไม่เกี่ยวข้องกันอีกต่อไป
การใช้ keys() method
เราสามารถใช้ keys() ดึงเฉพาะ key ของ dict ตัวนั้นๆออกมา ซึ่งอาจนำไปวน loop เพื่อแสดงผล หรือนำไปสร้างเป็น options ให้ user เลือก
now_showing = keys(current_movies)
print(now_showing)
# ผลลัพธ์ที่ออกมาจะเป็นแบบนี้
dict_keys(['equalizer 3', 'john wick 4', 'batman'])