views:

94

answers:

3

I have a class which is derived from a base class, and have many many lines of code

e.g.

class AutoComplete(TextCtrl):
    .....

What I want to do is change the baseclass so that it works like

class AutoComplete(PriceCtrl):
    .....

I have use for both type of AutoCompletes and may be would like to add more base classes, so how can I do it dynamically?

Composition would have been a solution, but I do not want to modify code a lot.

any simple solutions?

+5  A: 

You could have a factory for your classes:

def completefactory(baseclass):
    class AutoComplete(baseclass):
        pass
    return AutoComplete

And then use:

TextAutoComplete = completefactory(TextCtrl)
PriceAutoComplete = completefactory(PriceCtrl)

On the other hand depending on what you want to achieve and how your classes look, maybe AutoComplete is meant to be a mixin, so that you would define TextAutoComplete with:

class TextAutocomplete(TextCtrl, AutoComplete):
    pass
tonfa
I was thinking on similar lines, but it requires me to indent whole code, and as I said many many lines, objection looks trivial but I do wish I do not have to indent it
Anurag Uniyal
to not indent: Declare the classes hidden in the top level of the module as _TextAutoComplete and so on, then use the factory.
kaizer.se
@Anurag, using vim in block mode, or sed, it's really easy to reindent (and you should learn how to do it, it's very useful when programming in python)
tonfa
@tonfa thanks, I know how to indent code, but I just do not want to nest whole class code of 1000 lines 'Flat is better than nested.'
Anurag Uniyal
A: 

You could modify the __bases__ tuple. For example you could add another baseclass:

AutoComplete.__bases__ += (PriceCtrl,)

But in general I would try to avoid such hacks, it quickly creates a terrible mess.

nikow
+1  A: 

You could use multiple inheritance for this:

class AutoCompleteBase(object):
    # code for your class
    # remember to call base implementation with super:
    #   super(AutoCompleteBase, self).some_method()

class TextAutoComplete(AutoCompleteBase, TextCtrl):
    pass

class PriceAutoComplete(AutoCompleteBase, PriceCtrl):
    pass

Also, there's the option of a metaclass:

class BasesToSeparateClassesMeta(type):
    """Metaclass to create a separate childclass for each base.
    NB: doesn't create a class but a list of classes."""
    def __new__(self, name, bases, dct):
        classes = []
        for base in bases:
            cls = type.__new__(self, name, (base,), dct)
            # Need to init explicitly because not returning a class
            type.__init__(cls, name, (base,), dct)
            classes.append(cls)
    return classes

class autocompletes(TextCtrl, PriceCtrl):
    __metaclass__ = BasesToSeparateClassesMeta
    # Rest of the code

TextAutoComplete, PriceAutoComplete = autocompletes

But I'd still suggest the class factory approach already suggested, one level of indentation really isn't that big of a deal.

Ants Aasma