# [Tutor] A more Pythonic way to do this

D. Hartley denise.hartley at gmail.com
Fri Jul 1 02:13:19 CEST 2005

```..... it was a paren.

I was so worried that I just wasn't figuring it all out, that I had
tried to write elegant code and wasnt understanding the fundamentals,
and the only reason it didnt work was because I left out a paren.

I actually laughed until I cried.

Thanks for that.  And yes, it works now ;) it's lovely.

~Denise

> Here's the problem -->
> level)
>
>                         1,2           1        2
> 1      0
> you've put a braket after +30 which ends the Enemy call. The numbering is +1
> for opening braket -1 for closing so 0 is the end of the Enemy call if you
> understand this.
>
>
> On 6/30/05, D. Hartley <denise.hartley at gmail.com> wrote:
> >
> > Hey guys!
> >
> > I have a 'quest,' and at first glance this email looks long, but the
> > problem is probably not as complex as the length implies.  Please bear
> > with me, if I could get some advice on this particular problem, it
> > would go along way toward helping me be a better Python programmer.
> >
> > Some of you might remember, a few months ago, I was working on a space
> > invaders game for a birthday present.  One of the functions I really
> > wanted to add to the game was to change the enemy "ships" at each new
> > level. Because of my deadline and my newness to Python, I did this in
> > an extremely ugly way.  To give you an idea:
> >
> > the original main loop called:
> >     enemyship_sprites = createEnemies(screen, enemy_speed)
> >
> > createEnemies looks like this:
> >
> > def createEnemies(screen, speed):
> >    enemyship_sprites = EnemySprites(speed)
> >    for rows in xrange(5):
> >        for cols in xrange(8):
> (rows*40)+30), level)
> >    enemyship_sprites.draw(screen)
> >    return enemyship_sprites
> >
> > It creates an instance of EnemySprites (my holder class) which
> > contains code for when the ships hit bottom, when to update them, etc.
> > It also calls "Enemy()", which looks like this:
> >
> > class Enemy(pygame.sprite.Sprite):
> >    def __init__(self, startx, starty):
> >        pygame.sprite.Sprite.__init__(self)
> >        if level == 1:
> >        self.rect.centerx = startx
> >        self.rect.centery = starty
> >    def update(self, direction, go_down):
> >        jump = 40 # how much the enemies move to the right/left on
> > each jump
> >        if go_down:
> >            # if a ship is moving down on this round,
> >            # it doesn't move on the x-axys
> >            self.rect.move_ip((0, 5))
> >        else:
> >            # move a ship in the x-axys.
> >            # if direction=1, it moves to the right; -1 to the left
> >            self.rect.move_ip((jump * direction, 0))
> >        # maybe it's time for a shot? :)
> >        # the chances are 1/30
> >        dice = random.randint (0,30)
> >        global enemy_shot_sprites
> >        if dice == 1:
> >            shot = EnemyShot(self.rect.midtop)
> >
> >
> > Now, get ready for one of the uglier things you've probably seen lately
> (!!):
> >
> > Since I can only access the variable "level" from within the main
> > loop, for some reason I thought I couldnt use it in my class
> > definitions (which of course come before and are outside of the
> > mainloop).  So within the main loop, I did:
> >
> >                    if level == 1:
> >                        enemyship_sprites = createEnemies1(screen,
> enemy_speed)
> >                    elif level == 2:
> >                        enemyship_sprites = createEnemies2(screen,
> enemy_speed)
> >                    elif level == 3:
> >                        enemyship_sprites = createEnemies3(screen,
> enemy_speed)
> >                    elif level == 4:
> >                        enemyship_sprites = createEnemies4(screen,
> enemy_speed)
> >                    elif level == 5:
> >                        enemyship_sprites = createEnemies5(screen,
> enemy_speed)
> >                    elif level == 6:
> >                        enemyship_sprites = createEnemies6(screen,
> enemy_speed)
> >                    elif level == 7:
> >                        enemyship_sprites = createEnemies7(screen,
> enemy_speed)
> >                    elif level == 8:
> >                        enemyship_sprites = createEnemies8(screen,
> enemy_speed)
> >                    else:
> >                        enemyship_sprites = createEnemies9(screen,
> enemy_speed)
> >
> > And yes, I created 9 different createEnemies, all pretty much carbon
> > copies of each other except that they called Enemy1, Enemy2, Enemy3,
> > etc.  And then (you guessed it), I created 9 different Enemy
> > functions, too, so that each one could have its own (different)
> > bitmap.
> >
> > Now... this is just ridiculous.
> >
> > To my credit, I did actually know that at the time. But the day before
> > the birthday, I figured if I could make it work somehow, I would, and
> > I'd make it prettier later.  Now just happens to be that later ;)
> >
> > So now that I've got a little more Python experience under my belt
> > (not much, but a little), it occurred to me that when I call
> > createEnemies in the mainloop, I could pass in an argument 'level'.
> >
> > mainloop now starting off with:
> >     enemyship_sprites = createEnemies(screen, enemy_speed, level)
> >
> > level is one of my main loop variables, so it'll know what i'm talking
> > about and can take that variable and pass it in when it calls
> > createEnemies. (Btw, please forgive me if I mix up terms like argument
> > and variable or use them in the wrong places, I'm still getting used
> > to them!)  In any case, then I changed my createEnemies to look like
> > this:
> >
> > def createEnemies(screen, speed, level):
> >    enemyship_sprites = EnemySprites(speed)
> >    for rows in xrange(5):
> >        for cols in xrange(8):
> (rows*40)+30), level)
> >    enemyship_sprites.draw(screen)
> >    return enemyship_sprites
> >
> > Since the part that changes each level actually matters when the Enemy
> > function gets called (because that's where the bmps are loaded), I
> > made Enemy need 'level':
> >
> > class Enemy(pygame.sprite.Sprite):
> >    def __init__(self, startx, starty, level):
> >        pygame.sprite.Sprite.__init__(self)
> >        if level == 1:
> >        elif level == 2:
> >            (.................etc)
> >        self.rect.centerx = startx
> >        self.rect.centery = starty
> > (...............etc)
> >
> >
> > Now I know this email is getting hard to read ;)
> >
> > At this point I was thinking I'd have one createEnemies, called in the
> > mainloop, which would take the level and, when it called Enemy to
> > create the ships, use that level argument to determine which bmp to
> > use for the ship itself.  One createEnemies(), one Enemy(), there you
> > go.
> >
> > But now it's giving me an error when createEnemies is called, for the
> level) line,
> > saying __init__() (and this would be Enemy's init, correct?) takes
> > exactly 4 arguments (3 given):  and Enemy's init, as you can see,
> > takes (self, startx, starty, level).  But the first argument is just
> > 'self'!  I don't have to pass that in.... I never *did*, anyway, in
> > all my Enemy1, Enemy2, Enemy3 code...?
> >
> > I can send the full code for anybody who thinks that would be
> > clearer to look at (ha ha) - I was going to attach it here but it
> > would make the message too big for the list.  I know that going
> > through such a messy
> > problem like this is a pain, and questions like this don't always get
> > a lot of responses on the list.  My code worked, it was just messy,
> > and so I suppose I could just leave it alone. But I want to clean it
> > up: I want to make it more Pythonic, more organized, more efficient,
> > and would really love any advice anyone could offer.
> >
> > Heck, for all I know, I could just be needing to add a "self.___"
> > somewhere, heaven knows that has tripped me up before!
> >
> > Would love to hear from you guys, and thanks again,
> > Denise
> > _______________________________________________
> > Tutor maillist  -  Tutor at python.org
> > http://mail.python.org/mailman/listinfo/tutor
> >
>
>
```