-3

I'm trying to create a shmup in pygame. Instead of cluttering the level with calling enemies I want to delegate that to another class called Wave. When I want to create one object during a while loop I create a switch that starts True and becomes False after the object is called. When I do this with sprites that are assigned to groups this works, but with a custom class it doesn't.

Here is some pseudocode:

if self.wave_switch0 == True:
    wave = Wave()
    self.wave_switch0 = False

wave.run()

I tried creating a list and appending the wave, but this doesn't work.

waves = []
if self.wave_switch0 == True:
    wave = Wave()
    waves.append(wave)
    self.wave_switch0 = False

for wave in waves:
    wave.run()

Declaring the variable earlier in the code and assigning the value in the if-statement also doesn't work.

self.wave = None

if self.wave_switch0 == True:
    wave = Wave()
    self.wave_switch0 = False

wave.run()

Is there a way to keep the variable, while also using the switch so the wave isn't constantly being called? Or is there a better way to create an object only once during a while loop?

  • You want to learn about variable scope in python – Marcin Orlowski Apr 22 '23 at 13:23
  • I understand what variable scope is. I just don't know how I can keep the variable at the appropriate scope, or if it's even advisable to use switches like that, so I'm asking for feedback. – Maarten Bouwmans Apr 22 '23 at 13:26
  • Some possible tricks: Redefine the function within the function so the next time the function is called, it is actually calling the second function instead. Another method is to add an unused positional argument and initialize it as `[]` an empty list. append to it in the function and the next time you call it the list will be non-empty. – RufusVS Apr 22 '23 at 13:30
  • Thanks RufusVS! I tried the first trick and it works. It probably seems a silly question, but it's hard to understand what I'm doing when I'm just starting to learn programming. Thanks dude :) – Maarten Bouwmans Apr 22 '23 at 13:43

1 Answers1

0

Here's one way to remember the first call, add a dummy list argument:

def call_me_once(dummy=[]):
    if dummy:
        print ("Already called!")
        
    else:
        print ("First call!")
        dummy.append(0)
        
        
call_me_once()
call_me_once()
call_me_once()
call_me_once([]) # you can reset it this way
call_me_once()
call_me_once()
        

This will output:

First call!
Already called!
Already called!
First call!
Already called!
Already called!

Another tricky way is to redefine the function within itself:

def call_me_once():
    print ("First call!")
    globals()["call_me_once"] = lambda : print ("Already called!")
        
call_me_once()
call_me_once()
call_me_once()
        

Resulting in:

First call!
Already called!
Already called!
RufusVS
  • 4,008
  • 3
  • 29
  • 40
  • I can't upvote because I don't have the points, but thanks a lot :) It looks a lot cleaner than what I'm currently doing, creating a lot of switches to remember every action. I'll try to implement my calls like this. – Maarten Bouwmans Apr 22 '23 at 13:51
  • 2
    Careful of using a default value for a parameter as [] it can/will lead to unexpected behavior. https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument – JonSG Apr 22 '23 at 14:32
  • @JonSG Unexpected, for virtually everybody when they first encounter it. But it's not undefined or unpredictable. I'm sure there's plenty of code in the wild that depends on this behavior. – RufusVS Apr 22 '23 at 19:05