1
\$\begingroup\$

In one sentence

Is there a way to use class instantiation to return an instance of a subclass? (for ABC in particular)

Setup

I have an abstract base class with several sub-classes, which I can instantiate and use just fine. Here a reduced (and nonsensical) example to illustrate:

from abc import abstractmethod, ABC
from typing import Iterable


class Entity(ABC):

    @abstractmethod
    def describe(self) -> str:
        ...


class Person(Entity):
    def __init__(self, name: str):
        self.name = name

    def describe(self):
        return f"Hi I am {self.name}."


class Group(Entity):
    def __init__(self, names: Iterable[str]):
        self.names = names

    def describe(self):
        return f'Hello we are {" and ".join(self.names)}.'


p1 = Person("Alice")
g1 = Group(["Bob", "Chris"])

"Issue" and current solution

I don't always know in advance if I need a Person or a Group, and determine this in code. A function returns an instance of the appropriate class:

def create_entity(name_or_names: Union[str, Iterable[str]]):
    if isinstance(name_or_names, str):
        return Person(name_or_names)
    else:
        return Group(name_or_names)

p2 = create_entity("Alice")
g2 = create_entity(["Bob", "Chris"])

This works just fine as well.

Code review questions

I would prefer to keep the 'class instantiation pattern' as used for p1 and g1, but by using a common class. In other words, I'd rather write something like this

p3 = Entity("Alice") # returns Person 
g3 = Entity(["Bob", "Chris"]) # returns Group

so that it's clear I'm creating an object.

It feels like an antipattern to me to have a function, like create_entity here, return a class instance.

  • Am I being silly?
  • If no, is there a sensible way to do this? Either as part of the ABC itself or as part of a dedicated 'switchboard' subclass of the ABC.

I could go against naming conventions and simply rename the function to Entity (or something similar, to avoid a name collision) but that too doesn't sit right.

Many thanks

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Please edit your question so that the title describes the purpose of the code, rather than its mechanism. We really need to understand the motivational context to give good reviews. Thanks! \$\endgroup\$ Jan 11 at 13:34
  • 4
    \$\begingroup\$ We don't review "reduced and nonsensical examples"; we review real code. If you're able to show this code in its full, realistic context, it can be on-topic. As it is, it's too hypothetical to answer. \$\endgroup\$
    – Reinderien
    Jan 11 at 13:50
  • 2
    \$\begingroup\$ @Reinderien IMO it's not "too hypothetical to answer". This question seem to have everything it needs for a reasonable answer :) \$\endgroup\$ Jan 11 at 13:52
  • 3
    \$\begingroup\$ Your strategy is a good one for StackOverflow, but this is not StackOverflow - we love to see your code; and we love to see it in its entirety. A couple of hundred lines is quite easily digestible. The "distillation" process you describe is akin to the MCVE principal, and that's an SO-ism and not a CRSE-ism. The further you distill your code, the fewer hints we have as to why a thing exists the way it does, and the less meaningful commentary we can offer about your application design. \$\endgroup\$
    – Reinderien
    Jan 11 at 15:06
  • 1
    \$\begingroup\$ @GrajdeanuAlex Since the point of Code Review is to review code and help people improve their coding ability and not to answer how to questions, Reinderien is correct. There is obviously missing code which is a problem for a good code review. \$\endgroup\$
    – pacmaninbw
    Jan 11 at 15:21

Browse other questions tagged or ask your own question.