You can implement a singleton class that works properly quite easily. The advantage is that most people are familiar with singleton as a pattern, and it is a self contained chunk of code. The cache solution you provided works, but its functionality is not obvious and it feels very hacky to me. Somebody's going to initialize Whatever in another way down the line without using the cached function...

Another technique I've seen is to hide or overwrite the name of the class, such that client code only knows about the instance (and is expected to use it directly rather than doing any kind of access or instantiation). Of course, this doesn't give you lazy initialization unless you lazily import the module, at which point you would definitely be better off just using the module object directly.

There's also code out there which replaces the cached module object with a class instance in top-level code! This is especially used to work around the prior lack of module-level `__getattr__` (and `__dir__`), added in 3.7 (https://peps.python.org/pep-0562/). But you might still need it if for some reason you want to hook into the lower-level `__getattribute__`. And Andrew Moffat's `sh` package still does this (https://github.com/amoffat/sh/blob/develop/sh.py#L3635) even though it now only declares support for 3.8 and above. (Perhaps there was simply no clear reason to change it.)