You certainly can import child from parent and parent from child. The key to making this work is for child not to probe too deeply into parent from its module-level code, because the parent module is only partly loaded at the time that the Python runs the module-level code in child.
Here's what happens when you import child from parent and parent from child (assuming parent is loaded first):
- Code at the module level of
parent runs until it reaches a statement that loads child (either import child or from child import something). By "module level", I mean the statements that aren't within a class or function definition. The classes and functions defined at the module level will also be created as objects within the module. However, the functions and class methods themselves will not be run yet.
- When Python gets to the
import child statement (or equivalent) in parent's module-level code, it will stop running the parent code and begin running the module-level code in child. If child imports parent via import parent or from parent import something, it will get the parent module in its current, partially constructed state. So module-level code in child cannot access objects that are defined below import child in parent.py.
- Once
child's module-level code finishes running, control will return to parent below the import child statement, and Python will finish running all of the module-level code in parent.
This process will give you trouble if child's module-level code tries to access objects that are defined in parent after the import child statement (since parent is only partially finished when child loads). The solution to this is to import parent at the module level of child but defer accessing objects within parent from child until after child and parent have finished loading. In particular, instead of using from parent import something in child's module-level code, you may need to use import parent, then access parent.something from inside function or method code in child. This is safe to do because those functions and methods won't be run until after child and parent finish running, at which point all the elements of the parent module are correctly defined.
Here's an example of what I mean, using the setup you described in a comment. If you give more information on the code that is giving you problems, I could tailor this more closely.
Version 1 (won't work)
__main__.py:
from user import User
u = User()
user.py:
from data_manager import DataManager
...
class User:
def __init__(self, data_manager=None):
if data_manager is None:
data_manager = DataManager(user=self)
self.data_manager = data_manager
data_manager.py:
# next line will fail because user.py has been partly loaded
# and user.User doesn't exist yet
from user import User
...
class DataManager:
def __init__(self, user=None):
...
if user is None:
user = User(data_manager=self)
self.user = user
Version 2 (will work)
__main__.py:
from user import User
u = User()
user.py:
import data_manager as dm
...
class User:
def __init__(self, data_manager=None):
if data_manager is None:
data_manager = dm.DataManager(user=self)
self.data_manager = data_manager
data_manager.py:
import user as user_module
...
# this defines a class which will eventually create an instance
# of user.User, but it won't try to do that until control returns
# to __main__.py, by which point the `user` and `data_manager`
# modules are fully defined
class DataManager:
def __init__(self, user=None):
...
if user is None:
user = user_module.User(data_manager=self)
self.user = user
Note that references in your classes' __init__ methods don't get resolved until the class is actually instantiated. i.e., the user = user_module.User(data_manager=self) line does something like this: "look in the current module for an object called user_module; look in that object for a User attribute; construct an object of that class". The important thing is that data_manager can safely import the user module early on (the module exists already, even though it is only partly constructed), but the code above won't actually look for anything inside the user module until a DataManager object is instantiated, by which time user.User will be properly defined.