0

This is an embarrassingly simple code, but producing very weird result:

import os

print(dir(os))

def main():
    print(dir(os))
    import os

if __name__ == '__main__':
    main()

Note that there are 2 print(dir(os)) on lines 3 and 6. Very weirdly:

  1. Line 3 runs just fine and line 6 throws UnboundLocalError: local variable 'os' referenced before assignment.
  2. If I remove/comment out line 7 (import os again), the code runs just fine.

My Question:

  1. Why does the original code throw UnboundLocalError?
  2. Why does changing line 7 affect line 6? My understanding is that the Python interpreter runs sequentially and code never affect what comes before it.

Additional information:

  1. Replacing os with other modules gets the same result (e.g. numpy).
  2. Reproduced with Python 3.6 - 3.9.
  3. My best guess is since main is a function, the interpreter will scan the function first and record all symbols. In this case, in the initial scan, it marks a local variable os in the function, and in the second run, the local variable os is referenced before assignment, and hence the error. Because replacing line 7 with import os.path also gives the same error, but replace with "import os.path as osp` works fine again.
seekiu
  • 117
  • 1
  • 1
  • 6
  • `import` is an assignment (please see https://nedbatchelder.com/text/names1.html); the rest is explained by the usual logic (as per the linked duplicate). – Karl Knechtel Jul 02 '21 at 02:12

1 Answers1

2

import is an assignment statement. When a variable is assigned in a function, and you haven't declared it global, it's a local variable, so the global variable is not used. But you try to use os before you assign it with the import statement.

It's the same reason you'll get that error if you do:

myvar = 3

def main():
    print(myvar)
    myvar = 4

main()
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thank you, Barmar, for the quick response! Could you elaborate a bit more on the why part? I mean why does the interpreter behave this way such that change of a line affects what's before it. For example, in my additional information bullet point 3, I had a conjecture. Does that look correct? – seekiu Jul 02 '21 at 02:09
  • @seekiu yes your conjecture #3 looks right to me. – Mark Ransom Jul 02 '21 at 02:10
  • That's how Python scope works. It looks at the whole function to decide if a variable is local or global. @seekiu – Barmar Jul 02 '21 at 02:10