高校物理160203 views
りんご209490 views
中学英語811710 views
中学理科1630641 views
LaTeX962153 views
高校化学2924392 views
ヒストリア290598 views
高校倫理1440106 views
中学社会668760 views
世界の国564520 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

Python のジェネレータでメモリを節約する

ジェネレータの最大の利点は、メモリ効率の良さです。リストがすべての要素を一度にメモリに展開するのに対し、ジェネレータは必要なときに1つずつ値を生成します。この「遅延評価」により、大量のデータを扱う際にメモリを大幅に節約できます。

メモリ使用量の比較

100万個の数値を扱う場合の違いを見てみましょう。

import sys

# リスト:すべてメモリに展開
numbers_list = [x ** 2 for x in range(1_000_000)]
print(f"リスト: {sys.getsizeof(numbers_list):,} bytes")
# リスト: 8,448,728 bytes(約8MB)

# ジェネレータ:計算式だけを保持
numbers_gen = (x ** 2 for x in range(1_000_000))
print(f"ジェネレータ: {sys.getsizeof(numbers_gen)} bytes")
# ジェネレータ: 200 bytes

ジェネレータはデータそのものではなく「どうやってデータを生成するか」だけを覚えているため、要素数に関わらずサイズがほぼ一定です。

大きなファイルの処理

巨大なファイルを処理する際、全行をリストに読み込むとメモリ不足になることがあります。

リストで読み込む(危険)

メモリに全行を展開する。数GBのファイルで OutOfMemoryError の可能性。

ジェネレータで処理(安全)

1行ずつ読み込んで処理。ファイルサイズに関係なく一定のメモリで動作。

# 悪い例:全行をリストに読み込む
def read_all_lines(filename):
    with open(filename) as f:
        return f.readlines()  # 全行がメモリに

# 良い例:ジェネレータで1行ずつ
def read_lines(filename):
    with open(filename) as f:
        for line in f:
            yield line.strip()

# 使用例
for line in read_lines("huge_file.txt"):
    process(line)  # 1行ずつ処理

データパイプラインの構築

ジェネレータを連結すると、メモリ効率の良いデータパイプラインを作れます。

def read_numbers(filename):
    with open(filename) as f:
        for line in f:
            yield int(line.strip())

def filter_positive(numbers):
    for n in numbers:
        if n > 0:
            yield n

def double(numbers):
    for n in numbers:
        yield n * 2

# パイプラインを構築(まだ何も実行されない)
pipeline = double(filter_positive(read_numbers("data.txt")))

# ここで初めて1行ずつ処理が実行される
for result in pipeline:
    print(result)

各ジェネレータは1要素ずつ処理するため、ファイル全体がメモリに載ることはありません。

sum() や max() との組み合わせ

集計処理でもジェネレータを活用できます。

# リスト内包表記(一度リストを作成)
total = sum([x ** 2 for x in range(1_000_000)])

# ジェネレータ式(リストを作らない)
total = sum(x ** 2 for x in range(1_000_000))

後者はリストを作らずに直接合計を計算するため、メモリ使用量が大幅に少なくなります。

いつジェネレータを使うべきか

ジェネレータが適している

大量のデータを1回だけ処理する。全データを同時に必要としない。ストリーム処理やパイプライン。

リストが適している

データに何度もアクセスする。インデックスでランダムアクセスしたい。データ量が小さい。

メモリが限られた環境や、巨大なデータを扱う場合は、ジェネレータの活用を検討してください。