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.