Mutually referencing imports -- impossible?

M

Matthew Wilson

I started off with a module that defined a class Vehicle, and then
subclasses Car and Motorcycle.

In the Car class, for some bizarre reason, I instantiated a Motorcycle.
Please pretend that this can't be avoided for now.

Meanwhile, my Motorcycle class instantiated a Car as well.

Then I moved the Car and Motorcycle classes into separate files. Each
imported the Vehicle module.

Then I discovered that my Car module failed because the global
Motorcycle wasn't defined. The same problem happened in my Motorcycle
module. Car and Motorcycle can't both import each other.

In the beginning, when all three (Vehicle, Car, and Motorcycle) were
defined in the same file, everything worked fine.

I don't know how to split them out in separate files now though and I
really wish I could because the single file is enormous.

Any ideas?

Matt
 
G

Gary Herron

Matthew said:
I started off with a module that defined a class Vehicle, and then
subclasses Car and Motorcycle.

In the Car class, for some bizarre reason, I instantiated a Motorcycle.
Please pretend that this can't be avoided for now.

Meanwhile, my Motorcycle class instantiated a Car as well.

Then I moved the Car and Motorcycle classes into separate files. Each
imported the Vehicle module.

Then I discovered that my Car module failed because the global
Motorcycle wasn't defined. The same problem happened in my Motorcycle
module. Car and Motorcycle can't both import each other.

In the beginning, when all three (Vehicle, Car, and Motorcycle) were
defined in the same file, everything worked fine.

I don't know how to split them out in separate files now though and I
really wish I could because the single file is enormous.

Any ideas?

Matt

It is easy for imports to be mutually referencing. This presents no
problem to Python if the importing of one module is interrupted by the
import of another.

However, if one of them imports specific names from a module,
from ABC import abc
or
from ABC import *

then it's possible that the (interrupted) import of module ABC has not
progressed to the point that abc is defined.

The solution: Just
import ABC
and later reference ABC.abc

That being said, it is still a good design practice to structure your
modules hierarchically rather than a circularly.

Gary Herron
 
C

Carl Banks

I started off with a module that defined a class Vehicle, and then
subclasses Car and Motorcycle.

In the Car class,  for some bizarre reason, I instantiated a Motorcycle..
Please pretend that this can't be avoided for now.

Meanwhile, my Motorcycle class instantiated a Car as well.

Then I moved the Car and Motorcycle classes into separate files.  Each
imported the Vehicle module.

Then I discovered that my Car module failed because the global
Motorcycle wasn't defined.  The same problem happened in my Motorcycle
module.  Car and Motorcycle can't both import each other.

In the beginning, when all three (Vehicle, Car, and Motorcycle) were
defined in the same file, everything worked fine.

I don't know how to split them out in separate files now though and I
really wish I could because the single file is enormous.

Any ideas?

First thing to do is ask yourself:
Are the Car and Motorcycle being created at import time, or are they
being created after the imports by a function call?

If it's the former, then yes, it's impossible. You can't do this, for
instance:

car.py:
-----------------
import motorcycle
a = motorcycle.Motorcycle()
-----------------

motorcycle.py:
-----------------
import car
b = car.Car()
-----------------


However, you can stick them in functions and call them afterwards and
it will work:

car.py:
-----------------
import motorcycle
def create_motorcycle():
global a
a = motorcycle.Motorcycle()
-----------------

motorcycle.py:
-----------------
import car
def create_car():
global b
a = car.Car()
-----------------

vehicle.py
-----------------
import car
import motorcycle
car.create_motorcycle()
motorcycle.create_car()
-----------------


Second, if you're using from ... import statements, it won't work; you
should change it to use plain imports as I did above. So the
following wouldn't work :


motorcycle.py:
-----------------
from car import *
a = Motorcycle()
-----------------

car.py:
-----------------
from motorcycle import *
b = Car()
-----------------



Third, if Motorcycle and Car are inside packages, you still need to
avoid from ... import even just to import the module (unless you're
willing to hook into the import machinery). For example, if car.py,
motorcycle.py, and vehicle.py are all parts of the package carsim,
then you'd have to do this:

motorcycle.py:
----------------
import carsim.car
def create_car():
global a
a = carsim.car.Car()
----------------

and not

motorcycle.py:
----------------
from carsim import car
def create_car():
global a
a = car.Car()
----------------

This last limitation is due to a wart in the import logic.


Carl Banks
 
J

John Roth

I started off with a module that defined a class Vehicle, and then
subclasses Car and Motorcycle.

In the Car class,  for some bizarre reason, I instantiated a Motorcycle..
Please pretend that this can't be avoided for now.

Meanwhile, my Motorcycle class instantiated a Car as well.

Then I moved the Car and Motorcycle classes into separate files.  Each
imported the Vehicle module.

Then I discovered that my Car module failed because the global
Motorcycle wasn't defined.  The same problem happened in my Motorcycle
module.  Car and Motorcycle can't both import each other.

In the beginning, when all three (Vehicle, Car, and Motorcycle) were
defined in the same file, everything worked fine.

I don't know how to split them out in separate files now though and I
really wish I could because the single file is enormous.

Any ideas?

Matt

While it's possible for circular imports to work, it's very dangerous:
it's not always possible to tell what went wrong without tracking down
the process of the import step by step. There are more productive ways
of banging your head against the wall and going insane.

In your situation, it might be a whole lot easier to extract a common
superclass that both of your classes could inherit from.

John Roth
 
J

John Machin

I started off with a module that defined a class Vehicle, and then
subclasses Car and Motorcycle.

In the Car class, for some bizarre reason, I instantiated a Motorcycle.
Please pretend that this can't be avoided for now.

Meanwhile, my Motorcycle class instantiated a Car as well.

Then I moved the Car and Motorcycle classes into separate files. Each
imported the Vehicle module.

Then I discovered that my Car module failed because the global
Motorcycle wasn't defined. The same problem happened in my Motorcycle
module. Car and Motorcycle can't both import each other.

And they should not import each other.
In the beginning, when all three (Vehicle, Car, and Motorcycle) were
defined in the same file, everything worked fine.

You seem to have a strange notion of "worked fine".
I don't know how to split them out in separate files now though and I
really wish I could because the single file is enormous.

What is making a file with 3 classes "enormous"?? What is "enormous"?
Any ideas?

*WRONG WAY*
*GO BACK*

Your structure is not only bizarre, it is also (sticking with only 1
letter of the alphabet) a Byzantine, baroque, and broken concept.

Asking us to "pretend that this can't be avoided for now" is asking
us to aid and abet you in creating a meaningless and unmaintainable
monster. Consider adding Truck and Bus subclasses. Will each subclass
instantiate the other 3??? You should be able to add or remove a
subclass without having to modify all other subclasses.

The only rational solution is not to have the subclasses refer to each
other. Tell us *why* you think you need to have Car refer to
Motorcycle and vice versa, and we should be able to help you find a
way out.

Cheers,
John
 
J

John Machin

While it's possible for circular imports to work, it's very dangerous:
it's not always possible to tell what went wrong without tracking down
the process of the import step by step. There are more productive ways
of banging your head against the wall and going insane.

In your situation, it might be a whole lot easier to extract a common
superclass that both of your classes could inherit from.

Like the Vehicle class the OP mentioned?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top