I have a base class that has a method that creates an instance of a subclass that is called the same as the input string.
This worked before by putting the subclasses and the base class in the same file, and doing something like globals()[name]
.
Now, however, I've split up the subclasses into other files. They each have an import base
statement at the top, so I can't just simply import the subclasses in my base class or there'll be a chain of circular importing.
Is there any workaround for this?
In base.py:
from basefactory import BaseFactory
class Base:
def __init__(self, arg1, arg2):
...
def resolve(self, element):
className = typing.getClassName(element)
return BaseFactory.getInstance(className, element, self)
In basefactory.py:
from file1 import *
from file2 import *
...
class BaseFactory:
@staticmethod
def getInstance(name, arg1, arg2):
subclass = globals()[name]
return subclass(arg1, arg2)
In file1.py:
from base import Base
class subclass1(Base):
def foo(self):
return self.arg1
You can move the import
statement that is failing to the method that creates the subclass object.
From what I'm understanding, you have:
One solution would be to create a separate function / class for the factory method, and put it in a separate file from the base class. This file could import all the files for the base class and derived classes without the circular reference.
For example:
# base.py:
class baseClass():
def __init__(self):
self.name = "Base"
# sub1.py:
from base import baseClass
class sub1Class(baseClass):
def __init__(self):
self.name = "sub1"
# sub2.py:
from base import baseClass
class sub2Class(baseClass):
def __init__(self):
self.name = "sub2"
# factory.py:
from sub1 import sub1Class
from sub2 import sub2Class # should not create an error
mapping = {'sub1': sub1Class, 'sub2': sub2Class}
def create(baseType):
return mapping[baseType]
Actually, a better method might be to use type:
type(name, bases, dict)
returns a new type object. This is essentially a dynamic form of the class statement. The name string is the class name and becomes the __name__
attribute; the bases tuple itemizes the base classes and becomes the __bases__
attribute; and the dict
dictionary is the namespace containing definitions for class body and becomes the __dict__
attribute. For example, the following two statements create identical type objects:
>>> class X(object):
... a = 1
...
>>> X = type('X', (object,), dict(a=1))
Why not move resolve into a manager class? Have a look at the domain class in Class factory in Python. I'm not sure if resolve is needed... you can get the class name directly from self.__class__.__name__
, and use python functions like type()
and isinstance()
to check if they're particular types.
Also check out:
Can you use a string to instantiate a class in python?
Does python have an equivalent to Java Class.forName()?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With