Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I am trying to dynamically pick a parent class in Python 2.7:

GLOBAL_CLASS_NAME = 'b'


class A(object):
    def __init__(self, bar):
        print('this is A with {}'.format(bar))


class B(object):
    def __init__(self, bar):
        print('this is B with {}'.format(bar))


class C(object):
    def __init__(self, bar):
        print('this is C with {}'.format(bar))


class DynamicClass(object):

    def __new__(cls, class_name, *args, **kwargs):
        if class_name == 'a':
            new_cls = A
        elif class_name == 'b':
            new_cls = B
        elif class_name == 'c':
            new_cls = C
        else:
            raise ValueError('No test type defined in config')

        return new_cls


class MyClass(DynamicClass(GLOBAL_CLASS_NAME)):
    pass

foo = MyClass('baz')

print(isinstance(foo, B))
print(issubclass(MyClass, B))

Giving the output:

this is B with baz
True
True

This works as expected so far, however, I feel there are some serious design flaws going on.

Why am I doing this?

I have a config file which should alter the functionality of specific methods in certain classes. I have proposed to do this as follow:

  • I have a number of concrete implementations of a base class (A, B, C in my example), one of which are then inherited by a child class (MyClass).
  • The parent class must be selected by a variable in a config file (GLOBAL_CLASS_NAME).
  • The child class is then inherited by other classes, modifying the behavior of their methods.

My questions

Are there any design patterns I should look into which achieve this in an improved manner? Are there any gotchas here which are going to burn me? Is there a more pythonic way of achieving this?

share|improve this question
    
Can you update the post to explain the problem that you are trying to solve, please? What led you to choose this approach? Did you consider using the 3-argument form of type instead? –  Gareth Rees Jun 11 at 16:22
    
@GarethRees I've added a why to my question –  OhAuth Jun 11 at 16:33
    
The code in the post assigns GLOBAL_CLASS_NAME before defining MyClass. Is this also true in your use case? That is, are you able to load the configuration file before defining MyClass? (This kind of difficulty is why we discourage you from posting hypothetical or pseudo-code — when all you have is pseudo-code, it's hard to establish what the actual requirements are.) –  Gareth Rees Jun 11 at 16:43

2 Answers 2

To build classes dynamically, Python provides the 3-argument form of the type function. So you can write:

# Dictionary mapping configuration name to the corresponding class.
base_classes = dict(A=A, B=B, C=C)

# Create MyClass, inheriting from the class named by GLOBAL_CLASS_NAME.
MyClass = type('MyClass', (base_classes[GLOBAL_CLASS_NAME],), {})

If MyClass needs to have its own methods, then you can use multiple inheritance:

class MyBaseClass:
    def method(self, *args):
        pass

MyClass = type('MyClass', (MyBaseClass, base_classes[GLOBAL_CLASS_NAME]), {})

Having written that, I ought to add that choosing a base class at runtime seems like a dodgy idea. I can imagine scenarios in which dynamic creation of classes makes sense (for example, in an object–relational mapping system where you want to create classes corresponding to the relations), but in most use cases there is probably a simpler solution. It's impossible to be sure though, since you didn't tell us what your real problem was.

share|improve this answer

This works as expected so far, however, I feel there are some serious design flaws going on.

This is a dirty hack. You haven't shared your motivation to choose those approach. What you posted is the implementation of a probably poor design decision.

Are there any design patterns I should look into which achieve this in an improved manner?

The factory pattern comes to mind. Assuming you wasn't too create a bunch of objects that can be different classes but all extruding a common interface, then the factory could decide, probably based on parameters you peas to our, which exact class to use. The exact classes chosen should remain hidden from clients, the idea is that they will behave differently, as per their implementation.

Are there any gotchas here which are going to burn me?

Such dirty hacks are not normal. You would have to have a very strong argument to use such a hack, but I have a feeling you don't. Yes, there are gotchas, but it would be too hypothetical to ponder about them. I suggest to look for a different approach. After you eliminated better approaches, that can become a strong argument to go with this one.

If you post your more complete solution, we can give more concrete suggestions. For now, try the factory pattern. Or look at other creational patterns that might apply.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.