Python Academy · Oppitunti

__slots__ ja muistin optimointi

Käyttäkää __slots__-määrettä instanssikohtaisen muistin kulutuksen vähentämiseen.

Oppitunti 4/413 vaihetta

__slots__ ja muistin optimointi on ilmainen Python Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Python Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Python Academy-kurssilla on yhteensä 4 oppituntia.

Oletusarvoisen __dict__:n aiheuttama lisäkuormitus

Oletusarvoisesti jokainen Python-instanssi tallentaa attribuutit __dict__-sanakirjaan, mikä aiheuttaa huomattavan muistilisän — yleensä 200–400 tavua instanssia kohden.

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__:n määrittäminen

Määritelkää __slots__ attribuuttinimien sekvenssinä. Python varaa sanakirjan sijaan kiinteän kokoisen taulukon, mikä säästää muistia.

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__

Muistinsäästö

__slots__-määrittelyä käyttävä instanssi kuluttaa yleensä 30–50 % vähemmän muistia kuin sanakirjapohjainen instanssi — säästö on merkittävä, kun olioita luodaan miljoonia.

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)

Ei __dict__:a oletusarvoisesti

Slots-luokalla ei ole __dict__-sanakirjaa, joten siihen ei voi lisätä mielivaltaisia attribuutteja luomisen jälkeen.

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__:n säilyttäminen __slots__:n kanssa

Sisällyttäkää "__dict__" __slots__-määrittelyyn, jos haluatte säilyttää instanssikohtaisen sanakirjan ja samalla määrittää yleiset attribuutit etukäteen slotteina.

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

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

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

__weakref__ __slots__-määrittelyssä

Slots-luokat menettävät heikkojen viitteiden tuen. Lisätkää "__weakref__" __slots__-määrittelyyn, jos haluatte ottaa tuen uudelleen käyttöön.

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>

Periytyminen ja __slots__

Jos yliluokka ei käytä __slots__-määrittelyä, aliluokka saa silti __dict__-sanakirjan. Täyden muistinsäästön saavuttamiseksi koko luokkahierarkian on määritettävä __slots__.

class Base:
    __slots__ = ("x",)

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

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

Muistin käytön mittaaminen

Käyttäkää tracemalloc- tai pympler-kirjastoa todellisen muistin käytön mittaamiseen ennen __slots__-määrittelyn lisäämistä ja sen jälkeen.

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__ ja pickle-serialisointi

Slots-oliot voidaan pickle-serialisoida, jos määrittelette __getstate__- ja __setstate__-metodit, tai käyttämällä oletusarvoista pickle-protokollaa, joka käsittelee slotit automaattisesti Python 3:sta alkaen.

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

dataclasses ja __slots__ — Python 3.10+

Välittäkää slots=True parametrina koristelijalle @dataclass, niin __slots__ luodaan automaattisesti.

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

Milloin __slots__-määrittelyä kannattaa käyttää

Käyttäkää __slots__-määrittelyä, kun instansseja luodaan miljoonia, muistia on rajallisesti tai attribuuttien käytön nopeus on kriittinen. Jättäkää se pois yleiskäyttöisistä luokista, joissa joustavuus on tärkeämpää.

# 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

Pikatarkistus

Mitä tapahtuu, kun slotted-instanssille yritetään määrittää attribuutti, jota ei ole lueteltu __slots__-määrittelyssä?

Kertaus

__slots__ korvaa instanssikohtaisen __dict__-sanakirjan kiinteällä taulukolla ja säästää 30–50 % muistia. Sisällyttäkää "__dict__" tai "__weakref__", jos tarvitsette niitä. Koko periytymisketjun on käytettävä __slots__-määrittelyä täyden säästön saavuttamiseksi. Käyttäkää Python 3.10:stä alkaen muotoa @dataclass(slots=True).

Aloita maksutta

Opi Python tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
76
Oppitunnit
320

Usein kysytyt kysymykset

Onko oppitunti ”__slots__ ja muistin optimointi” ilmainen?

Kyllä – oppitunnin ”__slots__ ja muistin optimointi” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Python Academy-kurssin, päivitä CoddyKit PROhon. Python Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”__slots__ ja muistin optimointi”?

Käyttäkää __slots__-määrettä instanssikohtaisen muistin kulutuksen vähentämiseen. Harjoittelet Python Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Python Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Python Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”__slots__ ja muistin optimointi”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Python Academy-oppitunnilla?

Kyllä. Jokainen Python Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Miten Python-luokat luodaan
  2. Mukautettujen metaluokkien kirjoittaminen
  3. Deskriptorit: __get__, __set__, __delete__
  4. __slots__ ja muistin optimointi
← Takaisin: Python Academy