Is it a Pythonic class to keep track of its instances?

Take the following piece of code

class Missile:
    instances = []

    def __init__(self):
        Missile.instances.append(self)

      

Now take the code:

class Hero():
    ...
    def fire(self):
        Missile()

      

When the hero shoots, you need to create a rocket and add it to the main list. Thus, the hero object must reference the list when it fires. Here are a few solutions, although I'm sure there are others:

  • Make the list global,
  • Use a class variable (as above) or
  • The hero object has a link to the list.

I haven't posted this on gamedev because my question is actually more general: Is the previous code acceptable? Given this situation, is there a more pythonic solution?

+3


source to share


5 answers


Questions:

  • Does the Hero have any further control of the rocket after launch?
    • Yes -> save list with hero instance
    • No -> save it elsewhere
  • Does the rocket class need to know about rockets already in production to build a new rocket or to handle other rockets?
    • Yes -> save rocket class list
    • No -> save it elsewhere
  • Did you answer “No” to both of the above questions?
    • Yes → save the list as part of the game


There is nothing unique about keeping a list as part of a class if your reasons for doing so make sense.

+5


source


I have done this in the past for the same reason as you. I really don't see any problem with it.



It might be more appropriate in your case for the list to belong to the hero object, although

+2


source


Regardless of being Pythonic, I'd say good OO practice would require the Hero class to keep a rocket list.

(If I am missing something and one Missile

needs to know the others)?

Perhaps something like this:

class Hero():
    def __init__(self):
        self.missiles = []

    def fire(self):
        self.missiles.append(Missile())

      

If you want a "global" list of missiles, rather than one for each Hero

, I would suggest creating a static member variable instead:

class Hero():
    missiles = []

    def fire(self):
        Hero.missiles.append(Missile())

      

+2


source


Your code is fine and the first two solutions you suggested are acceptable (actually, don't get the third one though: which list is a "list"?).

Depending on your needs, and if there are many classes that require such a tracking system (e.g. bullets, missiles, mines ...), you can move this tracking logic into the class metaclass (classes used to instantiate classes).

Basically, you subclass a class type

and create your own "class constructor", then use the syntax:

__metaclass__ = my_metaclass_that_generate_classes_tracking_their_instantiation

      

in your class for tracking.


EDIT: Just read my comment on the original question. If you have more objects firing missiles of the same class, then the cleanest template to follow - IMO - should have an ech object (Hero, BadGuy, Allied ...) to keep the rocket object list. It simulates the world you describe and it will make your code easier to maintain ...

NTN!

+1


source


Giving a character to track the projectiles they fire might work fine, but it also means that whenever you delete that character, their projectiles disappear as well. If I remember correctly what happened in the Tiberian Sun when you destroyed the MLRS flood - if it had missiles in flight when it exploded, they would disappear.

Providing the symbol update function returns the projectile it (s) created, so the refresh loop can put them in the list of projectiles, might work fine too. Handling multiple projectiles per update can be as simple as always returning a list — it can be empty, or it can contain one or more projectiles.

Here's what I would suggest: store projectiles and characters (hero, allies, enemies, etc.) in the World object and pass a reference to this object to each character who needs to interact with it (by launching projectiles into the world, or by checking the nearest enemies). For every rocket your hero fires, he calls his addProjectile function in the world. If the hero needs to perform other actions that affect the rest of the game, the World object can provide the functionality to do this without having to clutter up the main update loop with special cases.

Of course, you are not limited to just one approach. You can combine them whenever you need. If you have homing projectiles, you can give them a reference to their target so that they can update their speed on every update call. If you have projectiles that cannot damage the one that fired them, you can link them to their "owner". If a character can only have 2 projectiles at a time (as in some older games), you can make the characters keep track of their active projectiles so they know when to stop firing. You can even let the projectiles track your "friends" if they are fired into an explosion so they can coordinate their movement to form quirky flowing patterns.;)

+1


source







All Articles