เปลี่ยนแปลงได้และเปลี่ยนแปลงไม่ได้ใน Python
บทความนี้อธิบายเกี่ยวกับการเปลี่ยนแปลงได้และเปลี่ยนแปลงไม่ได้ใน Python
YouTube Video
เปลี่ยนแปลงได้และเปลี่ยนแปลงไม่ได้ใน Python
"เปลี่ยนแปลงได้" และ "เปลี่ยนแปลงไม่ได้" หมายถึง ความสามารถในการเปลี่ยนแปลงของวัตถุ (object) การเข้าใจเรื่องนี้ช่วยในการ หลีกเลี่ยงข้อผิดพลาดที่ไม่คาดคิด และ การจัดการหน่วยความจำอย่างมีประสิทธิภาพ
อะไรคือเปลี่ยนแปลงได้?
เปลี่ยนแปลงได้ หมายถึงวัตถุที่สามารถ เปลี่ยนแปลงสถานะภายในหลังจากที่สร้างขึ้นแล้ว
ประเภทข้อมูลเปลี่ยนแปลงได้หลัก
list
dict
set
- คลาสที่ผู้ใช้กำหนดเอง (หาก attribute ของมันสามารถถูกแก้ไขได้)
ตัวอย่าง: การแก้ไข List
1numbers = [1, 2, 3]
2numbers[0] = 100
3print(numbers) # [100, 2, 3]
List เป็นวัตถุเปลี่ยนแปลงได้ และเราสามารถปรับเปลี่ยนองค์ประกอบภายในได้ตามต้องการ
อะไรคือเปลี่ยนแปลงไม่ได้?
เปลี่ยนแปลงไม่ได้ หมายถึงวัตถุที่ ไม่สามารถเปลี่ยนแปลงได้หลังจากที่ถูกสร้างขึ้นแล้ว การพยายามแก้ไขวัตถุดังกล่าวจะทำให้เกิดการสร้างวัตถุใหม่ขึ้นแทน
ประเภทข้อมูลเปลี่ยนแปลงไม่ได้หลัก
int
float
str
tuple
bool
frozenset
ตัวอย่าง: การแก้ไข String
1text = "hello"
2# text[0] = "H" # TypeError: 'str' object does not support item assignment
3
4text = "H" + text[1:] # Creates a new string
5print(text) # "Hello"
String เป็นวัตถุเปลี่ยนแปลงไม่ได้ ดังนั้นคุณไม่สามารถแก้ไขบางส่วนของมันได้
การเปรียบเทียบระหว่างเปลี่ยนแปลงได้และเปลี่ยนแปลงไม่ได้
1# Mutable example
2a = [1, 2, 3]
3b = a
4b[0] = 100
5print(a) # [100, 2, 3] -> a is also changed
6
7# Immutable example
8x = 10
9y = x
10y = 20
11print(x) # 10 -> x is unchanged
ดังที่แสดงในตัวอย่างข้างต้น วัตถุเปลี่ยนแปลงได้ถูกแชร์โดยการอ้างอิง (reference) ดังนั้น มันสามารถส่งผลกระทบต่อตัวแปรอื่นได้ ในทางกลับกัน วัตถุที่ไม่สามารถเปลี่ยนแปลงได้จะสร้างอินสแตนซ์ใหม่เมื่อมีการกำหนดค่าใหม่ โดยค่าต้นฉบับจะไม่ได้รับผลกระทบ
การตรวจสอบพฤติกรรมภายในโดยใช้ id()
ใน Python คุณสามารถใช้ฟังก์ชัน id()
เพื่อตรวจสอบ ID ของวัตถุ ID ของวัตถุคล้ายกับที่อยู่ในหน่วยความจำ
1# Immutable int behavior
2a = 10
3print(id(a)) # e.g., 140715920176592
4a += 1
5print(id(a)) # e.g., 140715920176624 -> ID has changed
6
7# Mutable list behavior
8b = [1, 2, 3]
9print(id(b)) # e.g., 2819127951552
10b.append(4)
11print(id(b)) # Same ID -> only the content has changed
ตามที่แสดง วัตถุใหม่จะถูกสร้างขึ้นสำหรับประเภทที่ไม่เปลี่ยนแปลงได้, ในขณะที่ ประเภทที่เปลี่ยนแปลงได้จะถูกแก้ไขในตำแหน่งเดิม
ฟังก์ชันและข้อควรระวังกับวัตถุที่เปลี่ยนแปลงได้และไม่ได้
เมื่อส่งวัตถุที่เปลี่ยนแปลงได้ไปยังฟังก์ชัน ข้อมูลต้นฉบับอาจถูกเปลี่ยนแปลงได้
ตัวอย่าง: ฟังก์ชันที่แก้ไขรายการ
1def modify_list(lst):
2 lst.append(100)
3
4my_list = [1, 2, 3]
5modify_list(my_list)
6print(my_list) # [1, 2, 3, 100]
ตัวอย่าง: ฟังก์ชันที่แก้ไขตัวเลข
ในทางกลับกัน การพยายามแก้ไขวัตถุที่ไม่สามารถเปลี่ยนแปลงได้จะส่งผลให้มีการสร้างวัตถุใหม่
1def modify_number(n):
2 n += 10
3
4my_number = 5
5modify_number(my_number)
6print(my_number) # 5 -> unchanged
ข้อควรพิจารณาในการใช้งานจริง
หลีกเลี่ยงการใช้วัตถุที่เปลี่ยนแปลงได้เป็นค่าเริ่มต้นของอาร์กิวเมนต์
1# Bad example
2def add_item(item, container=[]):
3 container.append(item)
4 return container
5
6print(add_item(1)) # [1]
7print(add_item(2)) # [1, 2] -> unintended behavior
8
9# Good example
10def add_item(item, container=None):
11 if container is None:
12 container = []
13 container.append(item)
14 return container
เนื่องจากค่าเริ่มต้นของอาร์กิวเมนต์จะถูกประเมินเพียงครั้งเดียวเมื่อประกาศฟังก์ชัน การใช้วัตถุที่เปลี่ยนแปลงได้อาจนำไปสู่ผลกระทบที่ไม่คาดคิด
สรุป
เพื่อความเข้าใจที่ลึกซึ้งเกี่ยวกับตัวแปรและประเภทข้อมูลใน Python การเข้าใจความแตกต่างระหว่างวัตถุที่เปลี่ยนแปลงได้และไม่ได้เป็นสิ่งสำคัญ การเข้าใจลักษณะเหล่านี้ช่วยให้คุณหลีกเลี่ยงพฤติกรรมที่ไม่ตั้งใจในโค้ดของคุณ และเขียนโปรแกรมที่มีความทนทานและอ่านง่ายขึ้น
คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย