10.5. Flyweight¶
EN: Flyweight
PL: Pyłek
Type: object
10.5.1. Pattern¶
In applications with large number of objects
Objects take significant amount of memory
Reduce memory consumed by objects

10.5.2. Problem¶
Imagine mapping application, such as: Open Street Maps, Google Maps, Yelp, Trip Advisor etc.
There are thousands points of interests such as Cafe, Shops, Restaurants, School etc.
Icons can take a lot of memory, times number of points on the map
It might crash with out of memory error (especially on mobile devices)

from dataclasses import dataclass
from enum import Enum
class PointType(Enum):
HOSPITAL = 1
CAFE = 2
RESTAURANT = 3
@dataclass
class Point:
x: int # 28 bytes
y: int # 28 bytes
type: PointType # 1064 bytes
icon: bytearray # empty: 56 bytes, but with PNG icon: 20 KB
def draw(self) -> None:
print(f'{self.type} at ({self.x}, {self.y})')
class PointService:
def get_points(self) -> list[Point]:
points: list[Point] = list()
point: Point = Point(1, 2, PointType.CAFE, None)
points.append(point)
return points
if __name__ == '__main__':
service = PointService()
for point in service.get_points():
point.draw()
# PointType.CAFE at (1, 2)
10.5.3. Solution¶
Separate the data you want to share from other data
Pattern will create a dict with point type and its icon
It will reuse icon for each type
So it will prevent from storing duplicated data in memory

from dataclasses import dataclass, field
from enum import Enum
from typing import Final
class PointType(Enum):
HOSPITAL = 1
CAFE = 2
RESTAURANT = 3
@dataclass
class PointIcon:
type: Final[PointType] # 1064 bytes
icon: Final[bytearray] # empty: 56 bytes, but with PNG icon: 20 KB
def get_type(self):
return self.type
@dataclass
class PointIconFactory:
icons: dict[PointType, PointIcon] = field(default_factory=dict)
def get_point_icon(self, type: PointType) -> PointIcon:
if not self.icons.get(type):
self.icons[type] = PointIcon(type, None) # Here read icon from filesystem
return self.icons.get(type)
@dataclass
class Point:
x: int # 28 bytes
y: int # 28 bytes
icon: PointIcon
def draw(self) -> None:
print(f'{self.icon.get_type()} at ({self.x}, {self.y})')
@dataclass
class PointService:
icon_factory: PointIconFactory
def get_points(self) -> list[Point]:
points: list[Point] = list()
point: Point = Point(1, 2, self.icon_factory.get_point_icon(PointType.CAFE))
points.append(point)
return points
if __name__ == '__main__':
service = PointService(PointIconFactory())
for point in service.get_points():
point.draw()
# PointType.CAFE at (1, 2)