__slots__でメモリ使用量を劇的に削減する裏技テクニック
Pythonをブラウザで実行しながら実践的に学ぶ
Pythonの基礎からソフトウェアアーキテクチャ,アルゴリズムなどの応用的な内容まで幅広く学べます。
ブラウザ上で直接Pythonコードを試すことができ、実践的なスキルを身につけることが可能です。
Pythonを書いていると、つい忘れがちになるのが「メモリ使用量」の問題です。
特に学習用の小さなスクリプトではあまり意識しないかもしれませんが、実際の業務や長時間動かすサービスでは、無駄なメモリ消費がパフォーマンス低下やサーバーコストの増加につながります。
私自身、エンジニア歴10年の中で「メモリの使い方ひとつでアプリの快適さが変わる」という場面を何度も見てきました。
その中で出会ったのが、Pythonの__slots__
というちょっとマイナーだけれど非常に強力な仕組みです。
この記事では、初心者の方でも理解できるように、なぜメモリ削減が必要なのか、そして__slots__
をどう活用するのかを順を追って解説していきます。
なぜメモリ使用量を削減する必要があるのか?¶
まず最初に、「そもそもメモリ削減なんて必要なの?」という疑問があるかもしれません。 パソコンやサーバーのスペックは年々向上しているので、多少のメモリ消費くらい気にしなくても…と考える人もいるでしょう。
しかし、現実にはこうした状況があります。
【同時に大量のデータを扱う】 例えば数百万件のログをオブジェクトに保持する場合、1つ1つのオブジェクトが無駄にメモリを食っていると、あっという間に何GBも消費してしまいます。
【クラウド環境でのコスト問題】 AWSやGCPのようなクラウドでは、メモリ量に応じて料金が変わります。 無駄な消費を削るだけでコストを抑えられるのです。
【パフォーマンスの安定性】 メモリ消費が多すぎると、ガーベジコレクション(不要メモリの回収)が頻発し、処理速度が落ちてしまいます。
私自身、過去に「開発環境では問題なかったのに、本番でユーザーが増えた途端にメモリ不足で落ちる」という経験をしました。 そんなトラブルを防ぐためにも、普段からメモリを意識することはとても大事なのです。
Pythonのクラスが持つ「隠れたコスト」¶
ここで少しPythonの仕組みについて触れておきましょう。 Pythonのクラスでオブジェクトを作ると、実は各インスタンスは辞書を内部的に持っています。
例えばこんなクラスを考えてみます。
class User:
def __init__(self, name, age):
self.name = name
self.age = age
このUserクラスのインスタンスを作ると、内部的には次のような辞書が自動で用意されます。
{“name”: “Alice”, “age”: 20}
便利ではあるのですが、この「辞書」が曲者です。 辞書は柔軟性が高い代わりに、メモリをそれなりに消費します。
つまり、大量のインスタンスを作ると、この辞書の分だけ無駄が積み重なってしまうのです。
そこで活躍するのが__slots__
です。
__slots__とは?¶
__slots__
は、Pythonのクラスに「このクラスで使う属性はこれだけ」と明示するための仕組みです。
つまり、「辞書を持たなくてもいいよ」とPythonに伝えることで、無駄なメモリを削減できるのです。
具体的な例を見てみましょう。
class User:
__slots__ = ("name", "age") # 属性を固定する
def __init__(self, name, age):
self.name = name
self.age = age
このクラスでは、name
とage
しか持てないようになります。
その代わり、内部に辞書を作らないので、その分メモリを節約できるのです。
実際にどれくらいメモリが削減されるのか?¶
理屈だけだとイメージが湧きにくいですよね。そこで、実際に比較してみましょう。
import sys
class UserNormal:
def __init__(self, name, age):
self.name = name
self.age = age
class UserSlots:
__slots__ = ("name", "age")
def __init__(self, name, age):
self.name = name
self.age = age
# インスタンスを作成
normal = UserNormal("Alice", 20)
slots = UserSlots("Bob", 25)
print("Normal:", sys.getsizeof(normal.__dict__))
print("Slots: __dict__なしで省メモリ")
出力結果は環境によって異なりますが、通常のクラスでは__dict__
が数十バイト〜数百バイトのメモリを使っています。
一方、__slots__
を使うとその辞書自体が存在しないので、オブジェクトのメモリ使用量を大幅に削減できます。
私が以前、大量のオブジェクトを扱う解析ツールを作ったとき、__slots__
を導入しただけでメモリ使用量が「数GB → 数百MB」にまで下がったことがありました。これには本当に驚きました。
どんなときに__slots__を使うべきか?¶
もちろん、常に__slots__
を使えばいいというわけではありません。
柔軟性と引き換えに制約があるからです。
使うべきなのはこんな場面です。
- 同じ型のオブジェクトを大量に生成する場合
- 属性が少なく、増えることがないとわかっている場合
- メモリ効率が最重要なシステム(IoTや組み込み用途など)
逆に、自由に属性を追加したい場合や、開発段階でまだモデルが流動的な場合には向きません。
__slots__のメリットとデメリット¶
ここで、メリットとデメリットを整理してみましょう。
項目 | メリット | デメリット |
---|---|---|
メモリ効率 | インスタンスごとに__dict__ を持たないので省メモリ |
属性を自由に追加できない |
パフォーマンス | 属性アクセスがやや高速になることがある | 多重継承時には制約がある |
コード管理 | 使える属性を明示でき、バグを減らせる | 柔軟性が失われ、開発初期の試行錯誤には不向き |
こうして見ると、大量データを扱う安定したシステムにとても向いていることがわかりますね。
まとめ¶
Pythonの__slots__
は、知っている人は少ないけれど、知っているだけで大きな差が出るテクニックです。
- インスタンスごとの辞書を省き、メモリ使用量を削減できる
- 属性アクセスも高速になる場合がある
- 柔軟性は制限されるので、使いどころを見極める必要がある
エンジニア歴10年の私の実感としても、「大量データを扱うシステムでは必須レベルの知識」と言えます。 もしあなたのプログラムがオブジェクトを大量に扱うのであれば、ぜひ試してみてください。
__slots__
を使いこなせるようになれば、Pythonプログラムの効率化に一歩先んじることができますよ。
ここまでお読みいただき、ありがとうございました!