Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should a class constructor return a subclass?

Should a class constructor return a subclass?

This is mostly a question about OOP style and python style. I have problem where I need to implement a general case solution and, for performance reasons, I need to implement an optimized solution for a specific input type. The input type depends on the user. Currently I've implemented this by sub-classing the general case solution to make the optimized solution. I've come up with the following example to help describe what I mean.

from collections import Counter

class MyCounter(object):
    """General Case Counter"""
    def __init__(self, seq):
        self.seq = seq

    def count(self, key):
        return sum(key == item for item in self.seq)


class OptimizedCounter(MyCounter):
    """Counter optimized for hashable types"""
    def __init__(self, seq):
        self.counter = Counter(seq)

    def count(self, key):
        return self.counter.get(key, 0)

counter = MyCounter(['a', 'a', 'b', [], [0, 1]])
counter.count([0, 1])
# 1

counter = OptimizedCounter(['a', 'a', 'b'])
counter.count('a')
# 2

My question is how do I design a smooth interface so that the user gets an appropriate instance without having to worry about how it's implemented. I've considered doing something like the following, but that feels ugly to me. Is there a more canonical or OOP way to do something like this?

class MyCounter(object):
    """General Case Counter"""
    def __new__(cls, seq):
        if hasOnlyHashables(seq):
            return object.__new__(OptimizedCounter)
        else:
            return object.__new__(MyCounter)
like image 438
Bi Rico Avatar asked Dec 26 '22 17:12

Bi Rico


1 Answers

Use a factory function that returns an instance of the appropriate class.

def makeCounter(seq):
    if hasOnlyHashables(seq):
        return OptimizedCounter(seq)
    else:
        return MyCounter(seq)
like image 99
BrenBarn Avatar answered Dec 29 '22 08:12

BrenBarn