1

I've built a fairly sizeable program in a single file. The size of the file was making it unworkable, so I decided to split into multiple modules, but have since had a major headache of variable scope. I've largely fixed it (with a fair bit of learning along the way), but I'm keen to understand good structuring to avoid future lessons learnt the hard way. There are a couple of specific points, but general advice is also welcome.

Modules that need to share the same namespace

I have two modules that seem to need to share the same namespace. One is the main flow of the program (which transfers data to and from objects, and calls the UI), the other is the UI (which responds to user input, calling the main flow).

Should each of these modules import the other, and then the main file import both? That doesn't seem particularly elegant to me.

from [modulename] import *

In the answers to this question:

Python: Sharing global variables between modules and classes therein

There is a suggestion that from [modulename] import * should be avoided.

Is it OK to use from [modulename] import * to build together a load of modules that just have class definitions? What are "safe" use cases?

asked Jun 2, 2013 at 18:26
3
  • Why do you think your two modules need to share the same namespace? Commented Jun 2, 2013 at 18:28
  • @BrenBarn so they can call each other. The program flow function does some work on the data, which dictates what needs to be presented to the user, so it calls the UI. Then the UI takes response from the user, and needs to call the program flow function to do some analysis/decision making. Commented Jun 2, 2013 at 18:41
  • Circular dependencies don't work in python. When module_a imports module_b, python hasn't gotten around to interpreting module_a past the "import module_b" statement. This means that you'll get name errors for anything that comes after the import in module_a. It sounds like you should either stick with your one big file, or spend some time redesigning, so you can factor out modules that don't depend on anything. Commented Jun 2, 2013 at 18:42

1 Answer 1

1

Modules that need to access each other's namespace is not the same as modules that need to share the same namespace. I can't think of anything you can do with from modulename import * that you can't do with import modulename. You just have to preface a lot of your names with modulename. That's a good thing, not a bad thing. It makes your code self-documenting, which is why from modulename import * is to be avoided.

You can have the UI and main flow modules import each other. The only way you'll run into problems is if you reference names between them outside of the scope of functions. For example

# mainflow.py
import ui # interpreter stops reading mainflow and starts reading ui
class Foo:
 ...
theUI = ui.UI()

# ui.py
import mainflow # mainflow already being loaded; interpretation of ui continues uninterrupted
def dosomething():
 myfoo = mainflow.Foo() # so far so good, not interpreted until the function is called
class Bar(mainflow.Foo): # mainflow.Foo not reached yet, error here
 ...
class UI:
 ...

On the other hand if ui happens to get imported first, then you get the error at theUI = ui.UI(), when all of mainflow has been interpreted but ui has only been interpreted as far as import mainflow. As long as you put all the references to each other inside functions, though, you can get along fine. E.g.

# mainflow.py
import ui
...
theUI = None
def initialize():
 global theUI
 theUI = ui.UI()

There's still a problem with the dependency between the classes; I recommend you don't do anything like that. But if you did, you could make the whole thing work with this strange approach:

# mainflow.py
...
theUI = None
def initialize():
 global theUI
 theUI = ui.UI()
import ui # Waht!? Crazy! Import at the bottom of a file. Now all of mainflow's names are guaranteed to exist and ui can access them.

Now with the first version of ui.py and the last version of mainflow.py, the program would compile and run. I don't really recommend the above; better organize your code so you don't have such dependencies. But if all you have is calls back and forth between functions in modules, you don't have to resort to such tricks.

There are more object-oriented designy ways to make your UI and your program flow not directly depend on each other, but such a redesign would be more involved than just copy and paste to files and prefacing names with module. I don't think you want to go overboard with your redesign unless you have a specific reason.

answered Jun 2, 2013 at 18:49
Sign up to request clarification or add additional context in comments.

2 Comments

While I agree with most of what you say, there's a mistake in the code of the last part. It's not necessary to have the theUI = None if you have the global theUI statement in the initialize() function.
It might be desirable if you ever have any code that could run before initialize. Then it can check if the UI has been initialized yet.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.