Flyweight Pattern — Core Concepts

What the Flyweight Pattern does

The Flyweight Pattern minimizes memory usage by sharing as much data as possible between similar objects. It splits object state into two categories:

  • Intrinsic state: Data that’s the same across many objects — stored once and shared
  • Extrinsic state: Data that’s unique to each object — stored separately

A flyweight object holds only intrinsic state. Extrinsic state is passed in from the outside when needed.

When memory matters

Python objects carry overhead. Each instance has a __dict__ (typically 56+ bytes), a type pointer, and a reference count. For a handful of objects, this is negligible. For millions, it dominates memory usage.

Consider a text editor rendering a document with 100,000 characters. Each character has a font, size, color, and style. If every character is a full object with all that data, memory usage explodes. With flyweights, characters sharing the same formatting point to one shared formatting object.

Intrinsic vs extrinsic — how to split

Ask two questions about each piece of data:

  1. Is it the same across many instances? → Intrinsic (share it)
  2. Is it unique per instance? → Extrinsic (pass it in)
Example domainIntrinsic (shared)Extrinsic (unique)
Game treesTexture, model, speciesPosition, health
Document charactersFont, color, stylePosition in text
Map markersIcon image, categoryLatitude, longitude
Product catalogDescription, image URLUser’s cart quantity

The flyweight factory

A flyweight factory ensures that identical intrinsic state is stored only once. When you request a flyweight with certain properties, the factory either returns an existing one or creates a new one and caches it.

This is similar to Python’s string interning — small strings that appear frequently are stored once and shared. The sys.intern() function makes this explicit.

Python’s built-in flyweights

Python already uses flyweight-like optimization:

  • Small integers (-5 to 256) are cached and reused
  • String interning for identifiers
  • __slots__ eliminates per-instance __dict__, saving memory per object
  • tuple and frozenset are immutable, making them natural flyweight candidates

When to use it

  • You have thousands or millions of similar objects
  • Most of the data in each object is shared with others
  • You can separate shared state from unique state cleanly
  • Memory is a constraint (embedded systems, large datasets, long-running servers)

When to skip it

  • You have few objects — the pattern adds complexity for no gain
  • Object state is mostly unique — nothing to share
  • You can solve the memory problem by changing data structures (using arrays or databases instead of objects)

Common misconception

“Flyweight is just caching.” Caching stores results to avoid recomputation. Flyweight shares object parts to avoid memory duplication. They’re related but solve different problems. A flyweight factory uses a cache internally, but the pattern is about structural sharing of object state.

The one thing to remember: Flyweight splits objects into shared (intrinsic) and unique (extrinsic) parts, so thousands of similar objects can exist without duplicating the data they have in common.

pythondesign-patternsoop

See Also

  • Python Adapter Pattern How Python's Adapter Pattern works like a travel power plug — making incompatible things work together.
  • Python Bridge Pattern Why separating what something does from how it does it keeps your Python code from becoming a tangled mess.
  • Python Builder Pattern Why building complex Python objects step by step beats cramming everything into one giant constructor.
  • Python Composite Pattern How the Composite Pattern lets you treat a group of things the same way you'd treat a single thing in Python.
  • Python Facade Pattern How the Facade Pattern gives you one simple button instead of a confusing control panel in Python.