A Single Instance of an Object?

Peter J. Holzer hjp-python at hjp.at
Mon Mar 11 19:37:14 EDT 2024


On 2024-03-11 16:53:00 -0400, Ivan "Rambius" Ivanov via Python-list wrote:
> I am refactoring some code and I would like to get rid of a global
> variable. Here is the outline:

...

> 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 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?

Just add a dict of Lookup objects to your module:

lookups = {}

def get_lookup(name):
    if name not in lookups:
        lookups[name] = Lookup()
    return lookups[name]

Then (assuming your module is also called "lookup", in all other modules
do

import lookup

lo = lookup.get_lookup("whatever")

...
v = lo.lookup("a key")

In your test cases where you need many different lookup tables use

lo = lookup.get_lookup("test1")
...
lo = lookup.get_lookup("test2")
...
lo = lookup.get_lookup("test3")

        hp

PS: You don't have to put that in a separate module but I think it's a
lot cleaner that way.

-- 
   _  | Peter J. Holzer    | Story must make more sense than reality.
|_|_) |                    |
| |   | hjp at hjp.at         |    -- Charles Stross, "Creative writing
__/   | http://www.hjp.at/ |       challenge!"
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://mail.python.org/pipermail/python-list/attachments/20240312/abfb2377/attachment.sig>


More information about the Python-list mailing list