Emanuele Marconato
Emanuele Marconato

Reputation: 13

Python3: Class Composition and derived methods

Good morning, I'm trying something like this:

class Fish:
  def __init__(self, name):
    self.name = name
  def swim(self):
    print(self.name,"is swimming!")

My ourpose is to extend the class to Aquarium, which cointains a dictionary of fishes:

class Aquarium(Fish):
  def __init__(self, **kwargs):
    self.fishes ={}
    for _, name in kwargs.items():
      self.fishes[name] = Fish.__init__(self,name)
  
  def how_many(self):
    print("In acquarium there are",len(self.fishes),"fishes")
  
  def all_swimming(self):
#???

Is it possible to implement something like Aquarium.swim() to use the method of all classes inserted? I tried it, but as result it prints out only of the last fish inserted. Any suggestion? How can I collect many Fish() inside Aquarium()? Are there better methods?

Upvotes: 0

Views: 239

Answers (2)

user212514
user212514

Reputation: 3130

It looks like you are confusing the idea of "is a kind of" and "contains". Writing class Aquarium(Fish) suggests that Aquarium is a kind of Fish, which it is not. An Aquarium contains fish. So, the Aquarium should not be derived from Fish.

I think this is more like your intentions:

class Fish:
    def __init__(self, name):
        self.name = name

    def swim(self):
        print(self.name, "is swimming!")


class Aquarium:  # An aquarium is not a kind of fish, rather it contains fish
    def __init__(self, **kwargs):
        self.fishes = []  # list of all fishes in the aquarium

        fishes = kwargs["fishes"]
        for fish_name in fishes:
            new_fish = Fish(fish_name)
            self.fishes.append(new_fish)  # add to your list

    def how_many(self):
        print("In aquarium there are " + str(len(self.fishes)) + " fishes")

    def all_swimming(self):
        print("The list of all fishes in the aquarium:")
        for fish in self.fishes:
            print("  " + fish.name)


a = Aquarium(fishes=["Nemo", "Dory"])
print(a.how_many())
a.all_swimming()

Upvotes: 2

Yes, it is possible. But I think this is a better way.

class Fish:
  def __init__(self, name:str):
    self.name = name
  def swim(self):
    print(self.name,"is swimming!")
    
    
class Aquarium():
  def __init__(self, fishes:Fish):
    self.fishes = []
    for fish in fishes:
      self.fishes.append(fish)
  
  def how_many(self):
    print("In acquarium there are",len(self.fishes),"fishes")
  
  def all_swimming(self):
      for fish in self.fishes:
          fish.swim()

Here is a list of suggestions that you may correct:

  1. An aquarium is not a fish. Do not inherit from it! If you need an aspect of the Fish class then split that class and make an composite.
  2. A dictionary is used to store a key and a value. But fish already knows that key. So why don't you use a list? Do you need the dictionary? If not use a list, it is easier to use (this is just my personal opinion).
  3. You used **kwargs. While this is usable nobody can clearly understand what exactly you want these parameters to be. Usually it is better to use a clearly defined set of parameters.
  4. Use typing. At least for the parameters. This is really helpful to understand your code better. Also you IDE might become more helpful if you do.

Upvotes: 1

Related Questions