ในบทความนี้ เราจะดูว่าเกิดอะไรขึ้นเมื่อเราอัปเดตค่าใน Tuple ซึ่งเป็น immutable จริงๆ เราจะสามารถรวมค่าใหม่กับค่าเก่าได้แต่จะโยนข้อผิดพลาด เราสามารถศึกษา bytecode ของข้อผิดพลาดและเข้าใจได้ดีขึ้นว่ากฎของ Tuple ทำงานอย่างไร
ก่อนอื่นเรากำหนด Tuple แล้วสั่งอัปเดตองค์ประกอบสุดท้ายดังนี้
ตัวอย่างโค้ด
>>> tupl = (5, 7, 9, [1, 4]) >>> tupl[3] += [6, 8]
ผลลัพธ์
การรันโค้ดข้างต้นจะได้ผลลัพธ์ดังนี้ -
Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object does not support item assignment >>> tupl (5, 7, 9, [1, 4, 6, 8])
ตอนนี้เพื่อศึกษา bytecode ของวิธีข้างต้น เราใส่โค้ดลงในฟังก์ชันและใช้เมธอด dis เพื่อแสดง bytecode เราได้ข้อผิดพลาดเดียวกันแต่อย่างละเอียดขึ้น
ตัวอย่างโค้ด
def immut_function():
tupl = (5, 7, 9, [1, 4])
tupl[3] += [6, 8]
immut_function()
ผลลัพธ์
การรันโค้ดข้างต้นจะได้ผลลัพธ์ดังนี้ -
TypeError Traceback (most recent call last)
in ()
2 tupl = (5, 7, 9, [1, 4])
3 tupl[3] += [6, 8]
----> 4 immut_function()
in immut_function()
1 def immut_function():
2 tupl = (5, 7, 9, [1, 4])
----> 3 tupl[3] += [6, 8]
4 immut_function()
TypeError: 'tuple' object does not support item assignment
ต่อไปเราแสดง bytecode ของฟังก์ชันข้างต้นเพื่อดูรายละเอียดของการกำหนดค่า Tuple และข้อผิดพลาด
ตัวอย่างโค้ด
import dis dis.dis(immut_function)
ผลลัพธ์
การรันโค้ดข้างต้นจะได้ผลลัพธ์ดังนี้ -
2 0 LOAD_CONST 1 (5)
3 LOAD_CONST 2 (7)
6 LOAD_CONST 3 (9)
9 LOAD_CONST 4 (1)
12 LOAD_CONST 5 (4)
15 BUILD_LIST 2
18 BUILD_TUPLE 4
21 STORE_FAST 0 (tupl)
3 24 LOAD_FAST 0 (tupl)
27 LOAD_CONST 6 (3)
30 DUP_TOPX 2
33 BINARY_SUBSCR
34 LOAD_CONST 7 (6)
37 LOAD_CONST 8 (8)
40 BUILD_LIST 2
43 INPLACE_ADD
44 ROT_THREE
45 STORE_SUBSCR
46 LOAD_CONST 0 (None)
49 RETURN_VALUE
ข้อสรุปคือ ไม่ควรใส่องค์ประกอบ mutable ลงใน Tuple แม้การกำหนดค่าจะเป็นไปได้ แต่จะโยนข้อยกเว้น ตามที่แสดงในขั้นตอนที่มีค่า 46 การกำหนดค่าล้มเหลวเพราะ Tuple เป็น immutable object