Skip to main content

Memory optimized implementations for the main Python Collection ABCs.

Project description

Opticol

Optimized collections (opticol) for Python. This package provides memory-efficient, slot-based implementations of Python's standard collection types:

  • Mapping / MutableMapping
  • Sequence / MutableSequence
  • Set / MutableSet

An example of the insight behind the package: an empty set (on Python 3.14) uses 216 bytes, but an empty object with empty __slots__ uses only 32 bytes. For applications creating thousands of small collections, opticol can dramatically reduce memory usage without API changes. The optimized types fully implement their respective collection ABCs.

When to Use Opticol

Opticol is beneficial when your application:

  • Creates many small collections (0-3 elements is the default optimization range)
  • Has memory constraints or needs to reduce memory footprint
  • Can benefit from transparent optimization without code changes

For general use cases where memory isn't constrained, standard Python collections are perfectly adequate.

Usage

To install opticol, simply do pip install opticol.

Quick Start (Convenience API)

The simplest way to use opticol is via the convenience functions:

import opticol

# Create optimized collections
optimized_list = opticol.seq([1, 2, 3])
optimized_set = opticol.set({1, 2, 3})
optimized_dict = opticol.mapping({'a': 1, 'b': 2})

# Mutable variants
mutable_list = opticol.mut_seq([1, 2])
mutable_set = opticol.mut_set({1, 2})
mutable_dict = opticol.mut_mapping({'a': 1})

# They implement standard ABCs
from collections.abc import Sequence, MutableSequence
assert isinstance(optimized_list, Sequence)
assert isinstance(mutable_list, MutableSequence)

By default, these functions optimize collections of size 0-3. Collections outside this range are returned unchanged as standard Python types. This method is useful for smaller scripts or applications.

Advanced (Projector API)

For custom optimization strategies or more complex applications, use projectors:

from opticol.projector import OptimizedCollectionProjector

# Create a projector with custom size range
projector = OptimizedCollectionProjector(min_size=0, max_size=5)

# Use it to optimize collections
optimized = projector.seq([1, 2, 3, 4, 5])

You can also create custom projectors by subclassing Projector. PassThroughProjector is a Projector implementation in the library that returns the argument as-is:

from opticol.projector import PassThroughProjector
from collections.abc import Sequence

class SelectiveProjector(PassThroughProjector):
    """Only optimize sequences, pass through everything else."""

    def seq(self, seq):
        # Your custom optimization logic
        return optimized_version(seq)

Projectors are intended to be pluggable DI components which allow for flexible and dynamic policies. Rather than relying on the convenience methods, logic which can benefit from the optimizations can consume a Projector which could be anything from a PassThroughProjector (and falls back to Python defaults) to a custom policy which uses domain specific knowledge to improve memory consumption.

Architecture

Opticol has a three-layer architecture:

  1. Factory Layer (opticol.factory): Generates optimized collection classes of arbitrary sizes using metaclasses and __slots__
  2. Projector Layer (opticol.projector): The main consumer API which acts as a pluggable policy pattern for different optimization strategies
  3. Convenience Layer (opticol): Simple functions backed by a default projector instance

This design allows you to use opticol in two ways:

  • Quick start: Use the convenience functions at the module level for immediate optimization with sensible defaults
  • Advanced: Create custom projectors to fine-tune optimization behavior for your use case

Details

Immutable Collections

Immutable collections (Sequence, Set, Mapping) are optimized for exact sizes. Each element is stored in a dedicated slot:

s = opticol.seq([1, 2])
# Internally: _item0 = 1, _item1 = 2, which is smaller than list([1, 2])

Mutable Collections

Mutable collections support overflow to standard types when exceeding capacity:

m = opticol.mut_seq([1, 2])  # Optimized, uses two slots to start
m.append(3)                  # Overflowed to use standard list internally
m.append(4)                  # Still uses standard list internally
m.pop()                      # Stays as list (no downgrade)
m.pop()                      # Reverts back to optimized storage

Optimization Propagation

Some collection operations return new instances such as slicing or set intersection or union operations. The convenience layer at the module level will propgate the optimization structure by default as if it were passed through the original optimization function.

seq = opticol.seq([1, 2, 3])
seq = seq[1:2]  # Has only one slot internally and technically an instance of a different class.

mut_seq = opticol.mut_seq([1, 2, 3])
mut_seq.extend([4, 5])  # Beyond optimization and overflowed into list internally
sub1 = mut_seq[3:4]  # Optimized instance with one slot.
sub2 = mut_seq[:]    # A simple list because the length is beyond the optimization point

mut_set = opticol.set({1, 2, 3})
bigger_set = mut_set | {4, 5, 6}  # Default python set
smaller_set = mut_set & {2, 3}    # Optimized python set for 2 elements

This decision was made so that optimizations are kept as much as possible. The alternative of always providing the python built-in is possible by creating a custom Projector, and may provide slightly better results for runtime and performance in specific applications.

Memory Savings

Below is a table which outlines the memory consumption differences per collection instance. As can be seen, sequence types benefit the least, while mapping, and set types benefit the most. The threshold whereby the savings for each collection type is no longer valuable is quite different and different applications may find different thresholds than those assumed by the convenience functions.

Collection Type Length Default (b) Optimized (b) Savings %
List 0 56 32 43
1 64 40 38
2 72 48 33
3 88 56 30
Dict 0 64 32 50
1 224 40 82
2 224 48 79
3 224 56 75
Set 0 216 32 85
1 216 40 81
2 216 48 78
3 216 56 74

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

opticol-1.0.0.tar.gz (29.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

opticol-1.0.0-py3-none-any.whl (20.3 kB view details)

Uploaded Python 3

File details

Details for the file opticol-1.0.0.tar.gz.

File metadata

  • Download URL: opticol-1.0.0.tar.gz
  • Upload date:
  • Size: 29.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for opticol-1.0.0.tar.gz
Algorithm Hash digest
SHA256 3c8a013d09054b4627f67d91d5b8aa24bee418d7e0e3de7a1c364a9a679b1282
MD5 9f897d859cf21a67b752d1a2ba49626e
BLAKE2b-256 18edf7e6331e5428dbbba0be4dbf711bdb93f697b6cbd18e50c82fc3b7457802

See more details on using hashes here.

File details

Details for the file opticol-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: opticol-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 20.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for opticol-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 af9c5201501ca6210c5c072d1f2577b4d39350eed7cf9ba3ee390b333cfccc5c
MD5 eff10bac2bd8b6ee8dcd0eb9046b70ef
BLAKE2b-256 87723f93331ce49b26d0194285a00245b15a0fb5ef62b175bf4465457ce07474

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page