Keith Hughitt
Keith Hughitt

Reputation: 4960

Python class factory problem referencing base class?

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?

Upvotes: 2

Views: 3133

Answers (2)

Josh Smeaton
Josh Smeaton

Reputation: 48720

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.

Upvotes: 1

Anton
Anton

Reputation: 1420

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 ()

Upvotes: 2

Related Questions