A Single Instance of an Object?

Ivan "Rambius" Ivanov rambiusparkisanius at gmail.com
Mon Mar 11 16:53:00 EDT 2024


Hello,

I am refactoring some code and I would like to get rid of a global
variable. Here is the outline:

import subprocess

CACHE = {}

def lookup(key):
    """"Runs the command cmd, parses its output, extract's the key's value,
    caches it and returns it. If the key has already been in the cache,
    returns its cached value. If the command cmd returns an error, the
    value is set to None and cached as None."""

    if key in CACHE:
        return CACHE[key]

    value = None

    cmd = f"mycmd {key}"
    proc = subprocess(cmd, capture_output=True, text=True, check=False)
    if proc.returncode == 0:
        value = proc.stdout.strip()
    else:
        logger.error("cmd returned error")

    CACHE[key] = value
    return value
...
def main():
    while True:
        keys = load_keys()
        for key in keys:
            call_function_that_call_function_that_calls_lookup(key)


The global cache variable made unit testing of the lookup(key) method
clumsy, because I have to clean it after each unit test. I refactored
it as:

class Lookup:
    def __init__(self):
        self.cache = {}

    def lookup(key):
        if key in self.cache:
            return self.cache[key]

        value = None

        cmd = f"mycmd {key}"
        proc = subprocess(cmd, capture_output=True, text=True, check=False)
        if proc.returncode == 0:
            value = proc.stdout.strip()
        else:
            logger.error("cmd returned error")

        self.cache[key] = value
        return value

Now it is easier to unit test, and the cache is not global. However, I
cannot instantiate Lookup inside the while- or for- loops in main(),
because the cache should be only one. I need to ensure there is only
one instance of Lookup - this is why I made it a global variable, so
that it is accessible to all functions in that script and the one that
actually needs it is 4 levels down in the call stack.

I have never done that in Python because I deliberately avoided such
complicated situations up to now. I know about the Singleton pattern,
but I have never implemented it in Python and I don't know if it is
Pythonish.

I am looking for the same behaviour as logging.getLogger(name).
logging.getLogger("myname") will always return the same object no
matter where it is called as long as the name argument is the same.

How would you advise me to implement that?

Regards
rambius

-- 
Tangra Mega Rock: http://www.radiotangra.com


More information about the Python-list mailing list