Need a solution or workaround to read and write the variable in moduleA from moduleB please. Here is the code:
moduleA
import moduleBvariable = 10def changeVariable():global variablevariable = 20def main():print("From moduleA, variable =", variable, " before change.")moduleB.main()print("From moduleA, variable =", variable, " after change.")if __name__ == "__main__":main()
moduleB
import moduleAdef main():print("From moduleB, variable =", moduleA.variable, " before change.")moduleA.variable = 20 # Try 1moduleA.changeVariable() # Try 2print("From moduleB, variable =", moduleA.variable, " after change.")if __name__ == "__main__":main()
When running moduleA we get:
- From moduleA, variable = 10 before change.
- From moduleB, variable = 10 before change.
- From moduleB, variable = 20 after change.
- From moduleA, variable = 10 after change.
Here is another example using static variables:
moduleAA
import moduleBBclass AA:variable = 0@staticmethoddef changeVariable():AA.variable = 20def main():AA.variable = 10print("From moduleAA, variable =", AA.variable, " before change.")moduleBB.main()print("From moduleAA, variable =", AA.variable, " after change.")if __name__ == "__main__":main()
moduleBB
import moduleAAdef main():print("From moduleB, variable =", moduleAA.AA.variable, " before change.")moduleAA.AA.variable = 20 # Try 1moduleAA.AA.changeVariable() # Try 2print("From moduleB, variable =", moduleAA.AA.variable, " after change.")if __name__ == "__main__":main()
When running moduleAA we get:
- From moduleAA, variable= 10 before change.
- From moduleBB, variable= 0 before change.
- From moduleBB, variable= 20 after change.
- From moduleAA, variable= 10 after change.
When you execute your moduleA
you're running it as a script - essentially a module with the name of __main__
, not as a 'normal' module, and that's how it gets loaded. If you go and look through sys.modules
as soon as you start it (before you import moduleB
) you ain't gonna find your moduleA
there but you'll find module __main__
(which will soon enough hold a variable
with value 10
).
Then when you import your moduleB
, it imports moduleA
- Python tries to find the loaded moduleA
but there isn't any, so it tries to load it from the disk and voila! it gets loaded, but this time as moduleA
. Python then looks for moduleB
that is imported from moduleA
, and since it's already there it doesn't make any fuss about it despite the cyclic dependency (and if you have something like that in your code - you're doing it wrong).
Anyway, since it's now loaded as moduleA
, its if __name__ == "__main__":
block evaluates to false so it doesn't cause any additional fuss. moduleB
proceeds with its execution, but it also doesn't match its if __name__ == "__main__":
block so it just gets loaded and sits there.
Now we're back in our __main__
representation of moduleA
- its if __name__ == "__main__":
block evaluates to true, so it calls its main()
function, which in turn calls moduleB
's main()
function, which then changes the variable
value but in moduleA
, not in __main__
. So, now when it gets back to __main__
and it tries to read its own variable
value it gets the unchanged version of 10
. But if you were to print out: print(getattr(sys.modules["moduleA"], "variable"))
you'd see that your moduleB
indeed changed the variable of moduleA
.
If you really want to force the change in main
, try having your moduleB
like:
import sysdef main():moduleA = sys.modules["__main__"] # this is the executing `moduleA` in your caseprint("From moduleB, variable =", moduleA.variable, " before change.")moduleA.variable = 20print("From moduleB, variable =", moduleA.variable, " after change.")if __name__ == "__main__":main()
Which will, running your test case from moduleA
, print out:
('From moduleA, variable =', 10, ' before change.')
('From moduleB, variable =', 10, ' before change.')
('From moduleB, variable =', 20, ' after change.')
('From moduleA, variable =', 20, ' after change.')
That's what's going on here, and the same is happening with your static vars example - you're consistently targeting the 'wrong' module form your moduleB
. Either way, please do not do this in any sort of a production code or any situation where other developers might end up having to mess with your code - cyclic redundancies are the bane of all things nice.