0

I am writing Python3 code that has different classes who extend a parent class.

I store data in a dictionary and depending of the value of a key I would like to build an object of a type or the other. I have an example here using "if statements":

class Vehicle:
    def __init__(self, d:dict):
        self.color = d["color"]
    def honk(self):
        print("**Abstract honk**")
#attempt at overloading, this function is overwritten later
def buildVehicle( decider:int, d ):
    return Vehicle(d)

class Car(Vehicle):
    def __init__(self, d:dict):
        self.color =        d["color"]
        self.numWheels =    4
        self.isAutomatic =  d["isAutomatic"]
    def honk(self):
        print("Boop boop!")
#attempt at overloading, this function is overwritten later
def buildVehicle( decider:float, d ):
    return Car(d)

class Boat(Vehicle):
    def __init__(self, d:dict):
        self.color =        d["color"]
        self.isCargo =      d["isCargo"]
    def honk(self):
        print("TUUUNNNN TUUUNNNN!")
#attempt at overloading, only this function is considered
def buildVehicle( decider:str, d ):
    return Boat(d)

if __name__=="__main__":
    d = {"type" : "car", "color" : "red", "isAutomatic" : False}
    v = None

    #current implementation
    if d["type"]=="car":
        v = Car(d)
    elif d["type"]=="boat":
        v = Boat(d)
    else:
        v = Vehicle(d)

    #what I would like to do
    ##v = Function( x, y), where Function returns the "correct" type
    ## of Vehicle depending on x, y


    v.honk()

Ideally I would want to get rid of the if-statements. I would like to use a single name to build objects of different types depending of the arguments, such that if a new class is added I do not need to change the existing code. I would be open to modifying the dictionaries to something else.

I tried overloading a method before realizing this was not possible in Python. For context I am a beginner in OOP. I tried looking up my question but I lack the keywords.

  • No, Python does not do "overloading", and type annotations *do not meaningfully affect the ordinary behaviour of the code* and are *merely hints* to *third-party tools*. Your current implementation is the right way to do things, although you can also explicitly check the `type` of things, or whether they `isinstance` of a particular type, in order to implement the logic. Just put that logic into your `buildVehicle`. – Karl Knechtel Jan 25 '22 at 13:01
  • 1
    "I tried overloading a method before realizing this was not possible in Python.... I tried looking up my question but I lack the keywords." No, you don't. You clearly already know the word `overloading`. The duplicate link I gave you is titled `Python function overloading`, and those are the words I used in the Stack Overflow search to find it. A [general Internet search with those terms](https://duckduckgo.com/?q=python+function+overloading) is also productive. – Karl Knechtel Jan 25 '22 at 13:05
  • @KarlKnechtel I think "right way to do things" is subjective. I explicitly say I want to avoid "if statements" because of design considerations. I believe there must be a better way. I am more interested in "best practice" from the pov of OOP. Is "mutliple dispatch" best practice for what I want to do? – Mehdi Slimani Jan 25 '22 at 13:50
  • @KarlKnechtel PS: I have read the linked question. I am just wondering if there is still a better way. From my pov multiple dispatch feels like forcing overloading in Python. – Mehdi Slimani Jan 25 '22 at 13:55
  • 1
    What you are trying to implement is *dispatch* based on the first argument to the function. "multiple dispatch" just means dispatch based on multiple things; *usually*, this means both the instance and one or more parameters of a method, but it can also mean multiple parameters of a function. Here, you want to dispatch based on one function parameter. Python does not support that natively, so you need one workaround or another. – Karl Knechtel Jan 25 '22 at 14:08
  • 1
    Python *does*, of course, support dispatch of methods based solely on the instance type: that's what you're probably used to calling "polymorphism". So if you could instead make `buildVehicle` a method of the `decider`, you'd be set. Unfortunately, it appears that you want this logic to depend on either the *value* of something, or vary depending on the type of something *which is of a built-in type*. – Karl Knechtel Jan 25 '22 at 14:09
  • 1
    That said, if the corresponding changes are acceptable to you, the refactoring is pretty straightforward. See e.g. https://refactoring.com/catalog/replaceConditionalWithPolymorphism.html. – Karl Knechtel Jan 25 '22 at 14:13
  • 1
    I realize now what I wanted to do was use polymorphism on a constructor. I understand it is not possible. The design pattern used in these cases is a factory method. – Mehdi Slimani Jan 25 '22 at 16:25

0 Answers0