โครงสร้างข้อมูล
Collection ในตัวของ Python
หัวข้อที่มีชื่อว่า “Collection ในตัวของ Python”Python มี container ประเภทใช้งานทั่วไปสี่ชนิดในตัวภาษา ไม่ต้อง import ใด ๆ
| ประเภท | Syntax | เปลี่ยนแปลงได้ | มีลำดับ | ซ้ำได้ | Hashable |
|---|---|---|---|---|---|
list | [1, 2, 3] | ได้ | ได้ | ได้ | ไม่ได้ |
tuple | (1, 2, 3) | ไม่ได้ | ได้ | ได้ | ได้เฉพาะเมื่อทุก element hashable |
dict | {"a": 1} | ได้ | ได้ (3.7+) | key: ไม่ได้ | ไม่ได้ |
set | {1, 2, 3} | ได้ | ไม่ได้ | ไม่ได้ | ไม่ได้ |
frozenset | frozenset({1, 2}) | ไม่ได้ | ไม่ได้ | ไม่ได้ | ได้ |
แต่ละประเภทมีจุดเด่นต่างกัน: list สำหรับลำดับที่แก้ไขได้, tuple สำหรับข้อมูลคงที่, dict สำหรับการค้นหาด้วย key, และ set สำหรับทดสอบสมาชิกภาพและ set algebra frozenset คือน้องของ set ที่เปลี่ยนแปลงไม่ได้ — แลกการเปลี่ยนแปลงกับความสามารถเป็น dict key หรืออยู่ใน set อื่นได้
Mutable กับ hashable คือขั้วตรงข้ามกัน ทุกประเภทที่เปลี่ยนแปลงได้ในที่นี้ (list, dict, set) ไม่ hashable — เพราะค่าของมันอาจเปลี่ยนหลังจากถูกใช้เป็น key ไปแล้ว ซึ่งจะทำให้สิ่งที่ hash มันไว้เสียหาย tuple hashable แบบมีเงื่อนไข: hashable ก็ต่อเมื่อทุก element ข้างในเป็น hashable ด้วย เพราะ tuple ที่มี element เปลี่ยนแปลงได้ (เช่น list) จะสืบทอดความไม่แน่นอนนั้นมา
เลือก collection ให้เหมาะสม
หัวข้อที่มีชื่อว่า “เลือก collection ให้เหมาะสม”- ใช้ list เมื่อต้องการ append, sort หรือเข้าถึงข้อมูลด้วย index
- ใช้ tuple เมื่อข้อมูลคงที่และตำแหน่งมีความหมาย (เช่น สี RGB, แถวในฐานข้อมูล)
- ใช้ dict เมื่อต้องการค้นหาด้วย key อย่างรวดเร็ว หรือจัดกลุ่ม attribute ที่มีชื่อโดยไม่ต้องสร้าง class
- ใช้ set เมื่อต้องการความเป็นเอกลักษณ์ หรือต้องการ union / intersection / difference
ตัวอย่างรันได้
หัวข้อที่มีชื่อว่า “ตัวอย่างรันได้”# --- list ---nums = [1, 2, 3, 4, 5]print('list:', nums)print('sum:', sum(nums))
# --- tuple unpacking ---coords = (10, 20, 30)x, y, z = coordsprint('tuple unpack:', x, y, z)
# --- dict (insertion order preserved since Python 3.7) ---scores = {'alice': 95, 'bob': 87, 'carol': 92}print('dict:', scores)print('alice score:', scores['alice'])
# --- set (duplicates removed automatically) ---unique = {3, 1, 4, 1, 5, 9, 2, 6, 5}print('set:', sorted(unique))
# --- hashability decides what can be a dict key or set member ---by_coords = {coords: 'a point'} # tuple works: it's hashableprint('tuple as dict key:', by_coords)
try: by_list = {nums: 'broken'} # list does not: it's mutable, unhashableexcept TypeError as e: print('TypeError:', e)Loading Python runtime (first run only)…
Mental Model
หัวข้อที่มีชื่อว่า “Mental Model”list [ 1 | 2 | 3 ] mutable, ordered -- reorder/replace freelytuple ( 1 | 2 | 3 ) immutable, ordered -- fixed once builtdict { k: v, ... } mutable, ordered keys -- lookup by hash(key)set { 1, 2, 3 } mutable, unordered -- membership by hash(value)frozenset immutable set -- hashable, unlike set
hashable = can compute a stable hash() -> usable as a dict key / set membermutable = value can change after creation without changing identitythese two are opposites: every built-in mutable type here is unhashableTrade-offs
หัวข้อที่มีชื่อว่า “Trade-offs”| สิ่งที่ได้ | ประโยชน์ | ต้นทุน |
|---|---|---|
list | มีลำดับ เปลี่ยนแปลงได้ index ได้ตามตำแหน่ง | membership test (in) เป็น O(n); insert/remove ที่ไหนก็ได้ยกเว้นท้ายเป็น O(n) |
tuple | เปลี่ยนแปลงไม่ได้ เบา และ hashable ถ้า element ของมัน hashable | โต หด หรือเรียงลำดับใหม่หลังสร้างไม่ได้ |
dict | lookup ด้วย key เฉลี่ย O(1) รักษาลำดับการแทรก | ทุก key ต้อง hashable |
set / frozenset | membership test เฉลี่ย O(1) ลบค่าซ้ำให้ฟรี | ไม่มีลำดับ — index ไม่ได้ ไม่รับประกันลำดับวนซ้ำ; set เองใช้เป็น dict key ไม่ได้ (มีแค่ frozenset ที่ทำได้) |
Common Misconceptions
หัวข้อที่มีชื่อว่า “Common Misconceptions”- “
{}สร้าง set ว่างเปล่า” — ความจริง:{}สร้าง dict ว่างเปล่า วิธีเดียวที่จะสร้าง set ว่างเปล่าคือset() - “collection ทั้งสี่รองรับ operation เดียวกันหมด” — ความจริง: มีแค่
listและdictเท่านั้นที่รองรับการ assign เข้าตำแหน่งที่มีอยู่แล้ว (lst[0] = x,d[k] = v);tuple,set, และfrozensetไม่รองรับการ assign เข้า item เลย - “เลือก collection type เป็นแค่เรื่อง style” — ความจริง: มันเปลี่ยน complexity class ของ operation ของคุณ (
O(1)เทียบO(n)lookup) และการรับประกันเรื่อง mutability ที่ผู้เรียกใช้พึ่งพาได้ — นี่คือการตัดสินใจเรื่อง correctness และ performance ไม่ใช่เรื่อง style - “tuple hashable เสมอเพราะ tuple เปลี่ยนแปลงไม่ได้” — ความจริง: hashable ก็ต่อเมื่อทุก element ข้างในก็ hashable ด้วย tuple ที่มี list อยู่ข้างในไม่ hashable
อ่านโค้ดที่ AI เขียน
หัวข้อที่มีชื่อว่า “อ่านโค้ดที่ AI เขียน”- โค้ดเขียน
seen = {}แล้วเรียก.add(...)บนมันหรือเปล่า?{}คือ dict ไม่ใช่ set —.addไม่มีอยู่บนdictและจะ raiseAttributeErrorตั้งแต่รันครั้งแรก - loop ทำการเช็ค
x in some_collectionซ้ำ ๆ กับสิ่งที่เริ่มต้นเป็นlistและโตขึ้นเรื่อย ๆ หรือเปล่า? นั่นคือการเช็คแบบO(n)ทุกรอบsetทำให้การเช็คเดียวกันเป็นO(1)โดยเฉลี่ย - tuple ถูกใช้ราวกับว่ารองรับ
.append()หรือการ assign เข้า item “แค่ครั้งนี้ครั้งเดียว” หรือเปล่า? ทั้งสองแบบ raise ทันที —AttributeErrorหรือTypeError - โค้ดสันนิษฐานว่าลำดับการวนซ้ำของ
setมีความหมายหรือทำซ้ำได้เสมอหรือเปล่า? ไม่จริง — มีแค่list,tuple, และdict(3.7+) เท่านั้นที่รับประกันเรื่องลำดับ
🐛 หา bug ในโค้ดนี้
def unique_ids(records): seen = {} result = [] for record in records: if record['id'] not in seen: seen.add(record['id']) result.append(record) return result
print(unique_ids([{'id': 1}, {'id': 2}, {'id': 1}]))เฉลย
seen = {} สร้าง dict ว่างเปล่า ไม่ใช่ set — {} เป็น dict literal เสมอใน Python; การเขียน set ว่างเปล่าคือ set() record['id'] not in seen ยังทำงานได้ (การเช็ค membership กับ dict จะเช็ค key ของมัน) แต่ seen.add(record['id']) ล้มเหลวทันที เพราะ dict ไม่มี method .add — มีแค่ set เท่านั้นที่มี ตรวจสอบแล้วบน Python 3.14: AttributeError: 'dict' object has no attribute 'add' วิธีแก้คือ seen = set()