0Pricing
Python Academy · บทเรียน

__slots__ และการเพิ่มประสิทธิภาพหน่วยความจำ

ใช้ __slots__ เพื่อลดหน่วยความจำส่วนเกินต่ออินสแตนซ์

__slots__ และการเพิ่มประสิทธิภาพหน่วยความจำ เป็นบทเรียน Python Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Python Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Python Academy มีบทเรียนทั้งหมด 4 บทเรียน

ค่าใช้หน่วยความจำส่วนเกินของ __dict__ โดยปริยาย

โดยปริยาย อินสแตนซ์ Python ทุกตัวจะจัดเก็บแอตทริบิวต์ไว้ในพจนานุกรม __dict__ ซึ่งใช้หน่วยความจำส่วนเกินมาก โดยทั่วไปประมาณ 200–400 ไบต์ต่ออินสแตนซ์

import sys

class Point:
    def __init__(self, x, y): self.x, self.y = x, y

p = Point(1, 2)
print(sys.getsizeof(p.__dict__))   # ~200 bytes

การประกาศ __slots__

กำหนด __slots__ เป็นลำดับของชื่อแอตทริบิวต์ Python จะจัดสรรอาร์เรย์ขนาดคงที่แทนพจนานุกรม จึงช่วยประหยัดหน่วยความจำ

class SlottedPoint:
    __slots__ = ("x", "y")

    def __init__(self, x, y):
        self.x = x
        self.y = y

p = SlottedPoint(1, 2)
print(p.x, p.y)   # 1 2
# p.z = 3   # AttributeError: no __dict__

การประหยัดหน่วยความจำ

เมื่อใช้ __slots__ โดยทั่วไปแต่ละอินสแตนซ์จะใช้หน่วยความจำน้อยกว่าอินสแตนซ์ที่ใช้พจนานุกรม 30–50% ซึ่งมีความสำคัญอย่างมากเมื่อสร้างออบเจ็กต์นับล้านรายการ

import sys

class Reg:
    def __init__(self, x, y): self.x, self.y = x, y

class Slotted:
    __slots__ = ("x","y")
    def __init__(self, x, y): self.x, self.y = x, y

print(sys.getsizeof(Reg(1,2)))      # ~56 bytes + ~200 dict
print(sys.getsizeof(Slotted(1,2)))  # ~56 bytes (no dict)

ไม่มี __dict__ โดยปริยาย

คลาสที่ใช้สล็อตจะไม่มี __dict__ ดังนั้นจึงไม่สามารถเพิ่มแอตทริบิวต์ตามอำเภอใจหลังจากสร้างอินสแตนซ์แล้วได้

class Config:
    __slots__ = ("host", "port")
    def __init__(self, h, p): self.host, self.port = h, p

c = Config("localhost", 8080)
# c.debug = True   # AttributeError
print(hasattr(c, "__dict__"))   # False

การคง __dict__ ไว้ด้วย __slots__

ใส่ "__dict__" ไว้ใน __slots__ เพื่อคงพจนานุกรมแยกสำหรับแต่ละอินสแตนซ์ ขณะเดียวกันก็ยังประกาศแอตทริบิวต์ที่ใช้บ่อยไว้ล่วงหน้าเป็นสล็อตได้

class Hybrid:
    __slots__ = ("x", "__dict__")

    def __init__(self, x):
        self.x = x

h = Hybrid(1)
h.extra = "dynamic"   # allowed
print(h.extra)

__weakref__ ใน __slots__

คลาสที่ใช้สล็อตจะสูญเสียการรองรับการอ้างอิงแบบอ่อน ให้เพิ่ม "__weakref__" ลงใน __slots__ เพื่อเปิดใช้การรองรับอีกครั้ง

import weakref

class Node:
    __slots__ = ("value", "__weakref__")
    def __init__(self, v): self.value = v

n = Node(42)
ref = weakref.ref(n)
print(ref())  # <Node object>

การสืบทอดและ __slots__

หากคลาสแม่ไม่ใช้ __slots__ คลาสลูกก็ยังคงมี __dict__ หากต้องการประหยัดหน่วยความจำอย่างเต็มที่ ลำดับชั้นทั้งหมดต้องกำหนด __slots__

class Base:
    __slots__ = ("x",)

class Child(Base):
    __slots__ = ("y",)   # no __dict__

class WithoutSlots(Base):
    pass   # gets __dict__ from object

การวัดประสิทธิภาพการใช้หน่วยความจำ

ใช้ tracemalloc หรือ pympler เพื่อวัดการใช้หน่วยความจำจริงก่อนและหลังเพิ่ม __slots__

import tracemalloc

tracemalloc.start()
points = [SlottedPoint(i, i) for i in range(100_000)]
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
print(f"Peak: {peak/1024/1024:.1f} MB")

__slots__ และการทำพิกเกิล

ออบเจ็กต์ที่ใช้สล็อตสามารถทำพิกเกิลได้ หากกำหนด __getstate__ และ __setstate__ หรือใช้โพรโทคอลพิกเกิลโดยปริยาย ซึ่งจัดการสล็อตโดยอัตโนมัติตั้งแต่ Python 3 เป็นต้นมา

import pickle

class Point:
    __slots__ = ("x", "y")
    def __init__(self, x, y): self.x, self.y = x, y

p = Point(3, 4)
data = pickle.dumps(p)
p2 = pickle.loads(data)
print(p2.x, p2.y)   # 3 4

ดาต้าคลาสพร้อม __slots__ — Python 3.10 ขึ้นไป

ส่ง slots=True ให้กับ @dataclass เพื่อสร้าง __slots__ โดยอัตโนมัติ

from dataclasses import dataclass

@dataclass(slots=True)
class Vector:
    x: float
    y: float

v = Vector(1.0, 2.0)
print(v.x, v.y)   # 1.0 2.0
print(hasattr(v, "__dict__"))   # False

ควรใช้ __slots__ เมื่อใด

ใช้ __slots__ เมื่อสร้างอินสแตนซ์นับล้านรายการ หน่วยความจำมีจำกัด หรือความเร็วในการเข้าถึงแอตทริบิวต์มีความสำคัญมาก หากเป็นคลาสสำหรับใช้งานทั่วไปที่ให้ความสำคัญกับความยืดหยุ่นมากกว่า ก็ไม่จำเป็นต้องใช้

# Good candidates:
# - Nodes in a large graph or tree
# - Records in a large dataset
# - High-frequency event objects

# Bad candidates:
# - Configuration objects added to ad-hoc
# - Classes that mix-in dynamic attributes

ตรวจสอบความเข้าใจอย่างรวดเร็ว

จะเกิดอะไรขึ้นเมื่อพยายามกำหนดแอตทริบิวต์ที่ไม่ได้ระบุไว้ใน __slots__ ให้กับอินสแตนซ์ที่ใช้สล็อต

สรุป

__slots__ แทนที่ __dict__ ของแต่ละอินสแตนซ์ด้วยอาร์เรย์ขนาดคงที่ จึงช่วยประหยัดหน่วยความจำ 30–50% หากจำเป็นต้องใช้ ให้ใส่ "__dict__" หรือ "__weakref__" ลำดับการสืบทอดทั้งหมดต้องใช้ __slots__ จึงจะประหยัดหน่วยความจำได้เต็มที่ ใน Python 3.10 ขึ้นไป ให้ใช้ @dataclass(slots=True)

คำถามที่พบบ่อย

บทเรียน “__slots__ และการเพิ่มประสิทธิภาพหน่วยความจำ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “__slots__ และการเพิ่มประสิทธิภาพหน่วยความจำ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Python Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Python Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “__slots__ และการเพิ่มประสิทธิภาพหน่วยความจำ”

ใช้ __slots__ เพื่อลดหน่วยความจำส่วนเกินต่ออินสแตนซ์ คุณปฏิบัติ Python Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Python Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Python Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “__slots__ และการเพิ่มประสิทธิภาพหน่วยความจำ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Python Academy นี้ได้ไหม

ได้ บทเรียน Python Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การสร้างคลาสของ Python
  2. การเขียนเมตาคลาสแบบกำหนดเอง
  3. ตัวบอกคุณสมบัติ: __get__, __set__, __delete__
  4. __slots__ และการเพิ่มประสิทธิภาพหน่วยความจำ
← กลับไปที่ Python Academy