Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม

วิธี Implement Immutable Data Structures ใน Python


ปัญหา

ต้องการ Implement Immutable Data Structures ใน Python

Immutable vs Mutable

Immutable Data Structures ป้องกันการแก้ไขข้อมูลพร้อมกันใน Parallel Programming Mutable (เช่น Array) เปลี่ยนได้ตลอดเวลา Immutable เปลี่ยนไม่ได้

ตัวอย่าง: Mutable Array (List)

# STEP 01 - Create a Mutable array
atp_players = ['Murray', 'Nadal', 'Djokovic']
print(f"Original: {atp_players}")
# Output: ['Murray', 'Nadal', 'Djokovic']

atp_players[0] = 'Federer'
print(f"Modified: {atp_players}")
# Output: ['Federer', 'Nadal', 'Djokovic']

เปลี่ยนค่าได้ง่าย อาจก่อให้เกิด Bug ใน Production หลาย Process ใช้ Array เดียวกัน

Tuple: Immutable (แต่มีข้อยกเว้น)

atp_players_tuple = ('Murray', 'Nadal', 'Djokovic')
atp_players_tuple[0] = 'Federer'
# Error: 'tuple' object does not support item assignment

แต่ถ้า Tuple มี Array (List) อยู่ภายใน ค่าภายใน List สามารถเปลี่ยนได้!

atp_players_array_in_tuple = (['Murray'], ['Nadal'], ['Djokovic'])
atp_players_array_in_tuple[0][0] = 'Federer'
# Result: (['Federer'], ['Nadal'], ['Djokovic'])

แก้ไข: ใช้ Tuple ของ Tuple

atp_players_tuple_in_tuple = (('Murray',), ('Nadal',), ('Djokovic',))
# Error เมื่อพยายามแก้ไข

NamedTuple: Built-in Immutable Class

from typing import NamedTuple

class GrandSlamsWithNamedTuple(NamedTuple):
    player: str
    titles: int

stats = GrandSlamsWithNamedTuple("Federer", 20)
stats.player = 'Djokovic'  # AttributeError: can't set attribute

# ใช้ _replace() สร้าง Copy ใหม่พร้อมแก้ไข
djokovic_stats = stats._replace(player="Djokovic", titles=17)

ตัวอย่างสมบูรณ์: ระบบร้านผัก

from typing import Tuple, NamedTuple

class Prices(NamedTuple):
    id: int
    name: str
    price: int

class Purchase(NamedTuple):
    purchase_id: int
    items: Tuple[Prices]

carrot = Prices(1, "carrot", 2)
tomato = Prices(2, "tomato", 3)
eggplant = Prices(3, "eggplant", 5)

tom_order = Purchase(1, (carrot, tomato))
total_cost = sum(item.price for item in tom_order.items)
print(f"Total Cost: {total_cost}$")  # Output: 5$