You might not need a class

Class-like functions: an alternative way of dealing with state

When writing Python, sometimes you need to store/manipulate state. There are two typical options:

  • Plain data structures [dictionaries, lists, sets etc.], passed to functions which perform mutation.
  • Instances of classes, i.e. objects, with the state as members, mutated using instance methods.

However, there is a third way:

  • A class-like function [I didn't come up with this term], with the state stored in a closure.

A class-like function is a "constructor" that returns "public" functions that can manipulate its state.

def MyClass(...)  # Capitalised to make it clear it's a "constructor"

    state_1 = ...
    state_2 = ...

    def func_1():
        nonlocal state_1
        ...

    def func_2():
        nonlocal state_2
        ...

    def func_3():
        ...

   return func_1, func_2  # Typically, 1 to 2 funcs

Used as, for example

func_1, func_2 = MyClass(...)

Such class-like functions have a few nice properties.

  • They are less flexible than classes. Yes: this is a nice property when dealing with state. You can't just define a few more methods, add @properties, override methods in a subclass etc. State is often seen a source of bugs, and sometimes it's better to really limit how it's mutated.
  • To test it, you are strongly pushed to only test the public interface, i.e. the functions returned from the function, rather than private implemenation details.
  • They encourage stronger separation of responsibilities between code that mutates state, and code that doesn't. I would be wary of too strongly touting benefits of "separation of responsibilities"; but separating stateful and non-stateful code, all-things-being-equal, is good.
  • You can name the returned functions whatever you like, even _ if not needed.
  • There are cases when it's faster.
  • They allow you to escape self-hell [although you may need more nonlocal].

As examples, lowhaio and aiodnsresolver both use class-like functions.