-2

Need a solution or workaround to read and write the variable in moduleA from moduleB please. Here is the code:

moduleA

import moduleB

variable = 10

def changeVariable():
    global variable
    variable = 20

def main():
    print("From moduleA, variable =", variable, " before change.")
    moduleB.main()
    print("From moduleA, variable =", variable, " after change.")

if __name__ == "__main__":
    main()

moduleB

import moduleA

def main():
    print("From moduleB, variable =", moduleA.variable, " before change.")
    moduleA.variable = 20 # Try 1
    moduleA.changeVariable() # Try 2
    print("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 moduleBB

class AA:
    variable = 0

    @staticmethod
    def changeVariable():
        AA.variable = 20

def main():
    AA.variable = 10
    print("From moduleAA, variable =", AA.variable, " before change.")
    moduleBB.main()
    print("From moduleAA, variable =", AA.variable, " after change.")

if __name__ == "__main__":
    main()

moduleBB

import moduleAA

def main():
    print("From moduleB, variable =", moduleAA.AA.variable, " before change.")
    moduleAA.AA.variable = 20 # Try 1
    moduleAA.AA.changeVariable() # Try 2
    print("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.
7
  • 3
    I already explained what's going on the last time you posted this. The solution is to stop relying on cyclic imports, global variables, and especially cross-module global variable dependencies. All of those things cause fragile, hard-to-reason-about code. Commented Jun 14, 2017 at 19:47
  • @user2357112 Thank you very much for the info. I don't understand how to solve this yet. So what you are saying is that it is impossible to modify this variable? I have a module containing an asynchronous API and another module containing the GUI. I need at least one dictionary shared between the two. This dictionary should be static. Commented Jun 14, 2017 at 20:32
  • The question of how to share data between modules has been asked many, many times. (Those just happened to be the first three I stumbled upon. There are plenty more.) Did you even try searching for "share variable between python modules"? Commented Jun 14, 2017 at 22:26
  • @John Y Thanks for the comment! I have searched for many things but not your exact phrase. I found many, many explanations but not many solutions. And the solutions that I found, did not work. In one of the three questions that you shared, there is one explanation that states that integers are passed by value when importing. Will investigate this further to see if we can have at least one clear solution to this problem. Commented Jun 14, 2017 at 23:15
  • @JohnY Tried the idea in the third question to use a list, but that didn't work either. Maybe I'm wrong, but it seems that none of the solutions you kindly supplied works. Thanks for trying. The answer by zwer seems to work though. Commented Jun 15, 2017 at 8:35

1 Answer 1

1

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 sys

def main():
    moduleA = sys.modules["__main__"]  # this is the executing `moduleA` in your case
    print("From moduleB, variable =", moduleA.variable, " before change.")
    moduleA.variable = 20
    print("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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much for the explanation and possible solution zwer! I almost gave up hope on this thing. The problem is that I don't want to run moduleA again. For instance if I have a GUI for moduleA and a async API for moduleB. Then it will open up another GUI. Is it possible to do this without cyclic referencing? What is the best solution to this problem? Have to go to bed soon. Thanks again.
@Yster - well, don't load your moduleA again - instead of import moduleA in your moduleB, use moduleA = sys.modules.get("__main__") assuming that your moduleA is still the main running script. Explaining how to avoid cyclical references is, I'm afraid, a bit out of the scope of these comments - it essentially requires to rethink how you want to design your system and if there is no way (and 99% of the time there is) around two separate entities depending on each other for some reason, create a broker between them to serve as an intermediary.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.