Reputation: 240
Two files, file1.py, file2.py. Can someone please explain why line 1.8 will print spam == 1 and not spam == 2 ? I've read all python circular import posts but I still don't understand this. Also, I don't understand why file1 is interpreted again from scratch when imported from file2. I was under the impression modules are not loaded again once they've been imported once.
# file1.py
print('1.1: initializing spam to 0')
spam = 0
spam += 1
print('1.4: spam == {}'.format(spam))
print('1.5: importing file2')
import file2
print('1.7: imported file2')
print('1.8: spam == {}'.format(spam)) # why 1 and not 2?
print('FILE 1 PARSED') # why is this executed twice?
# file2.py
print('\t\t\t2.1: importing file1')
import file1
print('\t\t\t2.3: imported file1, file1.spam == {}'.format(file1.spam))
file1.spam += 1
import file1
print('\t\t\t2.6: print from file2: file1.spam == {}'.format(file1.spam))
print('\t\t\tFILE 2 PARSED')
The output I'm getting is this:
1.1: initializing spam to 0
1.4: spam == 1
1.5: importing file2
2.1: importing file1
1.1: initializing spam to 0
1.4: spam == 1
1.5: importing file2
1.7: imported file2
1.8: spam == 1
FILE 1 PARSED
2.3: imported file1, file1.spam == 1
2.6: print from file2: file1.spam == 2
FILE 2 PARSED
1.7: imported file2
1.8: spam == 1
FILE 1 PARSED
PS. I appreciate circular imports are to be avoided, but I need to understand the logic.
Upvotes: 1
Views: 212
Reputation: 114481
Python import more or less goes as
What happens if you execute file1
is that the execution start as a main program then
file1
code imports file2
: since it was not present so the module object is created and execution of file2
beginsfile2
code imports file1
: since file1
was not present as a module then a module object is created and execution of file1
begins (as a module!)file1
code (as a module) imports file2
: the module is already present so the partially constructed file2
module object is returned immediatelyfile1
as a module completes execution and file2
resumes after importfile2
module completes execution and file1
as main program resumes after importIn other words there will be two instances of spam
: one inside the "main program" file1.py and one inside the module file1
.
Consider this simplified test case:
# p1.py
import p2, sys
p1d = {}
print id(p1d), id(sys.modules['p1'].p1d)
# p2.py
import p1
print "HERE"
running p1.py
you will get as output something like
18465168 18465168
HERE
17940640 18465168
the first two numbers are equal because the print
is executed from the p1
module while the second two numbers are different because print
is executed from p1
main program, that is a different instance.
PS: if you write intentionally code that does this (i.e. a main that indirectly import another instance of itself as a module) you should be put in jail :-)
Upvotes: 3
Reputation: 280778
When file1.py
is run as the main script, it is not the file1
module. It is the __main__
module. Pretend it's a completely separate file that happens to look exactly like the file1
module, because that's how Python treats it.
Python runs file1.py
as __main__
, which imports file2
, which imports file1
. Since the __main__
module is not considered the same as the file1
module, file1.py
runs again.
When file1
imports file2
, since file2
is already being imported, file1
fetches the half-constructed file2
module object and keeps going. It does not give file2
a chance to increase file1.spam
. This is why the first instance of line 1.8 prints 1.
When execution gets back to file2
, it increases file1.spam
, so line 2.6 prints 2. However, __main__.spam
is still 1. This is why when execution gets back to __main__
, the second instance of line 1.8 also prints 1.
Upvotes: 0