Search code examples
pythonmodulevariableslazy-loadingitunes

Lazy module variables--can it be done?


I'm trying to find a way to lazily load a module-level variable.

Specifically, I've written a tiny Python library to talk to iTunes, and I want to have a DOWNLOAD_FOLDER_PATH module variable. Unfortunately, iTunes won't tell you where its download folder is, so I've written a function that grabs the filepath of a few podcast tracks and climbs back up the directory tree until it finds the "Downloads" directory.

This takes a second or two, so I'd like to have it evaluated lazily, rather than at module import time.

Is there any way to lazily assign a module variable when it's first accessed or will I have to rely on a function?


Solution

  • You can't do it with modules, but you can disguise a class "as if" it was a module, e.g., in itun.py, code...:

    import sys
    
    class _Sneaky(object):
      def __init__(self):
        self.download = None
    
      @property
      def DOWNLOAD_PATH(self):
        if not self.download:
          self.download = heavyComputations()
        return self.download
    
      def __getattr__(self, name):
        return globals()[name]
    
    # other parts of itun that you WANT to code in
    # module-ish ways
    
    sys.modules[__name__] = _Sneaky()
    

    Now anybody can import itun... and get in fact your itun._Sneaky() instance. The __getattr__ is there to let you access anything else in itun.py that may be more convenient for you to code as a top-level module object, than inside _Sneaky!_)