Search code examples
pythonpython-importpython-module

Python: lazy submodule imports invalidate parent modules > UnboundLocalError - But why?


Considering the following code: I'm using a submodule allover my code and a special submodule (might be uber heavy to load) in only one function so I'm lazy importing:

import xml.etree

def y():
    print(xml.etree.__name__)

def x():
    print(xml.etree.__name__)

    import xml.dom
    print(xml.dom.__name__)

if __name__ == "__main__":
    y()
    x()

This will result in xml being unbound:

UnboundLocalError: local variable 'xml' referenced before assignment

(yes to fix it I can move the import up within the function OR do from xml import dom)

I'd love to know what happens here.
Apparently the imports are evaluated just before Python is entering the function.

What's the reasoning behind this?


Solution

  • Imports are not evaluated before entering the function, but the function body is parsed for assignments before execution. Any name bound in an assignment is considered a name local to the function, since the beginning of the body. As an import is an implicit form of assignment, the name xml just becomes local to the function. But you are using it before the import assignment. So the error is actually quite obvious.

    To fix it you can do as you say or simply use global:

    import xml.etree
    
    def y():
        print(xml.etree.__name__)
    
    def x():
        global xml
        print(xml.etree.__name__)
    
        import xml.dom
        print(xml.dom.__name__)
    
    if __name__ == "__main__":
        y()
        x()