✅ 結論
Pythonでは、int
や str
などの「イミュータブル(変更不可)なオブジェクト」を繰り返し書き換えると、メモリがムダに使われることがあります。
📘 例題:文字列を1文字ずつ追加したい
❌ よくある書き方(実は非効率)
s = ''
for i in range(1000):
s += str(i)
一見問題なさそうですが、実は毎回 s
に新しい文字列が作られていて、毎ループで新しいオブジェクトが生成されます。
🧠 どうして?
str
は immutable(変更不可) な型。
つまり、+=
などで変更しているように見えても、実際は「新しい文字列を作って s
を上書き」しているだけ!
💾 そもそも変数がメモリにどう保存されるかを知る
Python の変数は「オブジェクトへのラベル(参照)」です。
つまり、変数 a
は値そのものではなく、値が入っているメモリの場所(オブジェクト)を指している感じです。
変数a ─────▶ メモリ
メモリに 'hello'などのオブジェクトが格納されることで、変数aはhello
なんだな、と認識してくれる訳です。
メモリの場所を除くとこんな感じ(メモリアドレス)
# idメソッドで変数が格納されているメモリがわかります。
a = 'X' → id(a) = 1001
a += 'Y' → id(a) = 1050 ← 新しいオブジェクト!
a += 'Z' → id(a) = 1103 ← また新しい!
✅ 改善案:リスト+joinで効率化
l = []
for i in range(1000):
l.append(str(i))
s = ''.join(l)
メモリの場所を除くとこんな感じ(メモリアドレス)
この方法では、まずすべての文字列(例:'0', '1', '2', ...)を リスト l
に追加していきます。
l = [] → id(l) = 3001
l.append('0') → id(l) = 3001
l.append('1') → id(l) = 3001
... → id(l) = 3001 # ← ずっと同じ!
これなら、変数lはずっと同じオブジェクト(メモリアドレス)を持ちます。
そうすると文字列結合の時と違いオブジェクトを毎回生成しないので結果実行速度が速くなります。
補足
-
join
はメモリを抱えますが、同じオブジェクトを利用することで実行速度は速い -
str +=
はガベージコレクションによりメモリ消費は抑えられるものの、毎回新しいオブジェクトが生成されるため実行速度が遅くなる
📚 immutable な主な型
型 | 変更可能? |
---|---|
int |
❌ |
float |
❌ |
str |
❌ |
tuple |
❌ |
bool |
❌ |
✨まとめ
- Pythonの
str
,int
などは immutable(変更不可) -
+=
の繰り返しは 新しいオブジェクトを作り続けてる - 大量の繰り返し処理ではミュータブルである
list
などを使ってまとめて操作しよう!