nil_dib
nil_dib

Reputation: 51

Python modules importing behavior

Can someone explain this behavior?

A.py:

import B
values = []

if __name__ == "__main__":
    values.append('something')
    print(values)
    B.printValues()

B.py:

import A

def printValues():
    print(A.values)

Result:

['something']
[]

I expected:

['something']
['something']

Upvotes: 4

Views: 199

Answers (3)

Aran-Fey
Aran-Fey

Reputation: 43296

This is what happens:

  1. A imports B. This causes the code in B to be executed:
    1. A is imported. Because this is the first time A is being imported (A is not in sys.modules), all the code in A is executed.
      1. import B is executed. This does not execute the code in B, because Bis already in sys.modules.
      2. The empty list values is created.
      3. the if __name__=='__main__' block is not executed, leaving values empty.
    2. B now has a reference to a module A that differs from the main module. You can confirm this by adding import __main__; print __main__ is A to B. It will print False.

Upvotes: 2

JL Peyret
JL Peyret

Reputation: 12204

Yes, I am pretty sure A as main is not the same as the one in import A which ends up in sys.modules. So A exists twice, once as main, once as a module. Added a third module, C and you see that the B to C semantics meet your expectation - B and C share a common A.

A.py

import sys
print len(sys.modules), "len(sys.modules):A top"
import B, C
print len(sys.modules), "len(sys.modules):A after import B, C"

values = []


if __name__=="__main__":
    values.append('something')
    print "A:", values, 'id:',id(values)
    B.printValues()
    C.printValues()

B.py

import sys
print len(sys.modules), "len(sys.modules):B top"
import A
print len(sys.modules), "len(sys.modules):C after A import"

def printValues():
    print "B:", A.values, "id:", id(A.values)

C.py

import sys
print len(sys.modules), "len(sys.modules):C top"
import A
print len(sys.modules), "len(sys.modules):C after A import"

def printValues():
    print "C:", A.values, "id:", id(A.values)    

and this all outputs:

 42 len(sys.modules):A top
 43 len(sys.modules):B top
 44 len(sys.modules):A top
 45 len(sys.modules):C top
 45 len(sys.modules):C after A import
 45 len(sys.modules):A after import B, C
 45 len(sys.modules):C after A import
 45 len(sys.modules):A after import B, C
 A: ['something'] id: 4493313232
 B: [] id: 4493269616
 C: [] id: 4493269616               

Upvotes: 1

Hiroki Kumazaki
Hiroki Kumazaki

Reputation: 388

In short, it is a kind of closure.

you can add print any place to observe import behavior.

A.py

print("before import B")
import B
print("start execute A as " + __name__)

values = []

if __name__=="__main__":
    values.append('something')
    print "values=" + str(values)
    B.printValues()
    B.appendValue("hello")
    B.printValues()
    print "values=" + str(values)

print("finished execute A as " + __name__)

B.py

print("start runnig B")
import A

def printValues():
    print "A.values=" + str(A.values)

def appendValue(new_value):
    A.values.append(new_value)

print "A.values=" + str(A.values)

print("finish running B")

it gives result

before import B
start runnig B
before import B
start execute A as A
finished execute A as A
A.values=[]
finish running B
start execute A as __main__
values=['something']
A.values=[]
A.values=['hello']
values=['something']
finished execute A as __main__

A.values seen from B.py is another instance of data. It is not A.py's values. there is another namespace between combination of program & __name__.

Upvotes: 0

Related Questions