0

I have two files, blah.py containing

def blah():
    print("External blah")
    return "6"

and test.py containing

def blah():
    print("Internal blah")
    return "5"

if __name__ == '__main__':
    try:
        from blah import blah
    except:
        pass
    num = blah()
    print(num)

When I run this, I get

External blah
6

When I make blah.py inaccessible by renaming it to blaat.py, I get

Internal blah
5

Now, if I change test.py to

def blah():
    print("Internal blah")
    return "5"

def blater():
    try:
        from blah import blah
    except:
        pass
    num = blah()
    print(num)

if __name__ == '__main__':
    try:
        from blater import blater
    except:
        pass
    blater()

it works when blah.py is accessible, but I get an error message when blah.py is not accessible:

Traceback (most recent call last):
  File "./test.py", line 27, in <module>
    blater()
  File "./test.py", line 16, in blater
    num = blah()
UnboundLocalError: local variable 'blah' referenced before assignment

Why is that? What subtle difference in calling a function am I missing?

dehulst
  • 13
  • 3

1 Answers1

0

I think this link Python local variable compile principle should help you to understand what happens (all three answers and comments are helpful).

To summarize, the names are added to a scope during compilation and not during excution. Therefore, in your example, even if import fails, the name will be added to the scope.

In the first case, it's not a problem cause the name blah (create by function's definition in test.py) and the name blah (create by import statement) are in the same scope.

In the second case, the name blah (create by function's definition in test.py) is added to the global scope and the name blah (create by import statement) is added to the blater's local scope. So, even if the import fail, there is still the name blah in the blater's local scope and it prevents Python to search blah in global scope. Since blah has not been set, the UnboundLocalError is thrown.

If you want to go deeper into the subject, here is some links which helped me to better understand :

Introduction to python bytecode

dis module documentation

inspect module documentation

Python Data model (to understand how names are stored)

Halkiam
  • 51
  • 3