How do I know when to make something a class instead of an instance of a class? For example:
If I'm creating a space game (I'm not), and I want the environment to be the Universe, I'd write:
class Universe:
def __init__(self):
pass
Now let's say I'd like to fill my Universe with Galaxies, so I'd make a Galaxy subclass, with size and name parameters:
class Galaxy(Universe):
def __init__(self, size, name):
super().__init__(self):
self.size = size
self.name = name
pass
Next, I'd like to make Planets. If this were the case, I should make a subclass of the Galaxy subclass right?
class Planet(Galaxy):
def __init__(self, type, climate):
super().__init__(self, size, name):
self.type = type
self.climate = climate
pass
From here I'd like to make the Planet types, or "families". What's the best way to go about this? Another subclass of a subclass? Each planet will contain resources that are unique to that family of planets. Should I then make this:
class PlanetType(Planet):
resources = []
def __init__(self, resources):
super().__init__(self, type, climate)
self.resources = resources
pass
CodePudding user response:
So this is not specific to Python, it's more of a core idea of OOP(Object Oriented Programming)
How do I know when to make something a class instead of an instance of a class?
Answer : In your example Universe is the superclass , and you want to create the notion of Planets. If Planet inherits (subclass) from Universe that means they have an "is" relationship. I'm going to bring another popular example here to illustrate my point.
Let's say you have a class Car. Maserati would be a subclass(would inherit) from this superclass because a maserati IS a Car. If you wanted to represent Wheels as a class then it wouldn't make sense to say that Wheels IS a Car. A car HAS wheels. So Wheels Class should be an instance variable in Car. So back to your example. A Universe HAS galaxies and a Galaxy HAS planets. But a planet IS NOT a galaxy and a galaxy IS NOT a Universe.
CodePudding user response:
So, your first problem here is trying to make a class hierarchy of something that is fundamentally not suitable for it. When you're inheriting from another class, ask yourself "Is a SubClass a type of Class?". In your case, "Is a Galaxy a type of Universe?" and "Is a Planet a type of Galaxy?" are both clearly false.
In the cases you've got here, all the classes should contain the lower level types; a Universe
might contain a list
of Galaxy
s, which in turn contain a list
of Planet
s. I don't know exactly what you mean by a PlanetType
here (it seems perfectly possible for a Planet
to have an attribute, possibly an enum.Enum
, describing the type and a list
of resources), so I doubt it's a case for a subclass, but if it really is useful (e.g. you need methods that appear on all Planet
s but behave differently by the type), it might be reasonable to declare:
class GasGiant(Planet):
...
class RockyPlanet(Planet):
...
or the like, since "Is a GasGiant a type of Planet?" does in fact have an answer of "Yes". That said, I'd be wary of changing the prototype of the initializer even then; look up the Liskov substitution principle. Basically, you never want to be in a scenario where something expects a Planet
(that might really be one of the subclasses) but only works on some of the three Planet
classes, breaking if passed a different one.