Skip to content

InvestmentSystems/class-only-design

Repository files navigation

class_only_design

Build Status codecov

Tools for class only design.

A 'Class Only Design' is an attempt to merge some aspects of Object Oriented and Functional programming. Specifically, it:

  • allows you to group like functions and attributes in a common namespace,
  • lets you use inheritance to override certain functions, e.g., to implement the template pattern,
  • embraces the functional concept of immutability over changing state.

A class only class is, in other words, an approach for creating an immutable singleton object.

Installation

pip install class_only_design

The class_only decorator enforces class only design:

from class_only_design import ClassOnly

class VeryFunctional(ClassOnly):
    attribute = 5
    
    @classmethod
    def method(cls):
        return a_big_computation(cls.attribute)

It makes the class uninstantiable:

instance = VeryFunctional()

Traceback (most recent call last):
    ...
TypeError: Class Only classes cannot be instantiated

And also immutable:

VeryFunctional.attribute = 6

Traceback (most recent call last):
    ...
TypeError: Class Only classes are immutable

It'll also prevent you from adding methods that are used to instantiate classes:

class AwesomeClass(ClassOnly):

    def __init__(self):
        "Create an awesome instance!"
        
Traceback (most recent call last):
    ...
TypeError: ('Class Only classes cannot define __init__', <class '__main__.AwesomeClass'>)

Conceptually, a class_only class can have only one state. However, creating that initial state may be expensive, and you may not want to incur that expense at class creation time. For example, consider the following example:

class Methodology(ClassOnly):
    config = read_large_config_file()
    
    @classmethod
    def process(cls):
        for setting in cls.config:
            # do work

The time cost of calling read_large_config_file is incurred when Methodology is created, which for most classes means module load time. To address this issue, class_only provides the constant decorator. Decorating a method with @constant creates a class property that is called at most once. Using constant, the above example becomes:

from class_only_design import constant

class Methodology(ClassOnly):

    @constant
    def config(cls)
        return read_large_config_file()
    
    @classmethod
    def process(cls):
        for setting in cls.config:
            # do work

In the second example, read_large_config_file isn't called until Methodology.process is. Note that @constant ensures that the config method is only ever executed once, even if Methodology.process is called multiple times.