__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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การสร้างคลาสของ Python
- การเขียนเมตาคลาสแบบกำหนดเอง
- ตัวบอกคุณสมบัติ: __get__, __set__, __delete__
- __slots__ และการเพิ่มประสิทธิภาพหน่วยความจำ