2

I recently came across a Python class factory implementation that fit a problem I am working on really well. The only difference is that I wanted have the base and sub classes in different packages.

When I try to do this, however, I run into a problem whenever I try to load the base class.

Structure:

BaseClass.py

from subclasses import *

def NewClass():
    """Map Factory"""
    for cls in BaseClass.__subclasses__():
        print "checking class..."

class BaseClass(object):
    def __init__(self):
        print("Building an abstract BaseMap class..")

subclasses/__init__.py

__all__=['SubClass']

subclasses/SubClass.py

from BaseClass import BaseClass
class SubClassA(BaseClass):
    def __init__(self):
        print('Instantiating SubClassA')

When I try to import BaseClass though I get the following error:

       1 #import BaseClass

 ----> 2 from BaseClass import BaseClass
       3 class SubClassA(BaseClass):
       4     def __init__(self):
       5         print('Instantiating SubClassA')

 ImportError: cannot import name BaseClass

I also tried using "import BaseClass" and then subclassing "BaseClass.BaseClass" but that resulted in a different error:

      1 import BaseClass
----> 2 class SubClassA(BaseClass.BaseClass):
      3     def __init__(self):
      4         print('Instantiating SubClassA')

AttributeError: 'module' object has no attribute 'BaseClass'

Finally, If I just try to create the subclass directory there is no problem. It is only when I try to import the BaseClass module that things go wrong.

Any ideas?

Community
  • 1
  • 1
Keith Hughitt
  • 4,860
  • 5
  • 49
  • 54
  • "a different error."? Which different error? Please include this error, also. Also, your indentation seems wrong on the BaseClass.py example. Please check it carefully. All code must be indented. And preceded by a blank line. You have a `from subclasses import *` that could be code, but it could also be a part of the question. – S.Lott Apr 16 '11 at 11:36
  • Thanks S. Lott. I fixed the issues you mentioned. I originally thought that adding the second error might be too much so I left it out. The output is up now. – Keith Hughitt Apr 16 '11 at 11:42
  • "adding the second error might be too much"? That's not really possible. If you had another error, you **must** document the error. Anything else is unacceptable because you've omitted part of the problem. – S.Lott Apr 18 '11 at 00:50

2 Answers2

2

Some experimenting appears to show that the problem is import recursion. Making the import statement in BaseClass.py conditional solved the problem for my tests:

if __name__ == '__main__':
    from subclasses import *

prevents the recursion and python appears satisfied with this.

[EDIT]

A better solution is to have the NewClass method in a separate file:

something.py

from BaseClass import BaseClass
from subclasses import *

def NewClass():
    """Map Factory"""
    for cls in BaseClass.__subclasses__():
        print ("checking class...")

NewClass ()
Anton
  • 1,422
  • 1
  • 11
  • 15
  • Hi Anton, thanks for the suggestion. Unfortunately this prevents the error, but breaks the class factory. For example, if you then try and call "BaseClass.NewClass()" nothing will happen because no subclasses were imported. – Keith Hughitt Apr 16 '11 at 11:59
  • @Keith: Your design is broken in that case, try to disentangle your code so there is as little dependency from one module to the other. – XORcist Apr 16 '11 at 12:10
  • 1
    Putting the function and base class in separate files did the trick. Thanks for the help :) – Keith Hughitt Apr 16 '11 at 13:44
1

Without more information, it appears that your module BaseClass is not directly on the python path. BaseClass is able to find the sub classes, because they exist in a directory directly below BaseClass. The converse is not true.

A relative import should fix this issue.

from .. BaseClass import BaseClass

The .. will go up a directory, and look there (kind of like file paths). The alternative is to put BaseClass directly on the PYTHONPATH.

Having two different modules depending on each other sounds like not so great an idea though to be honest. Better off having the subclasses register with the BaseClass.

Edit:

What I meant by 'registering with the base class' is something like the following:'

# baseclass.py
subclasses = []
def register(cls):
    subclasses.append(cls)


# subclass.py
class SubClassA(BaseClass):
    ...

baseclass.register(SubClassA)

Now BaseClass doesn't need to know about all the different subclasses. They register to be used, and the BaseClass is able to use them without knowing about them before hand.

Josh Smeaton
  • 47,939
  • 24
  • 129
  • 164
  • Hi Josh, what other information could you use? The above should describe all of the code and file/directory structure. What do you mean by registering the subclasses with the BaseClass? Also, I tried the relative import but got a new error: "ValueError: Attempted relative import beyond toplevel package" – Keith Hughitt Apr 16 '11 at 11:53