Error opening IDLE on Mac OS X 10.6

10 Jan, 2015

Lucas writes (excerpted):

When I try to open IDLE as instructed on page 11 I get an error message.

Error dialog

Any suggestions?

It depends on which version of Python you're running, but if you've installed the latest (3.4.2), then instead of putting the following in Automator:

open -a "/Applications/Python 3.4/IDLE.app" --args -n

Try putting this instead:

/Library/Frameworks/Python.framework/Versions/3.4/bin/idle3.4 -n

The reason the text in the book doesn't work is a difference between Automator in versions of OS X prior to 10.7 (I believe 10.7, anyway) and later versions of the operating system.


Incrementing photo filenames

28 Dec, 2014

Emmeline writes:

I'm twelve and I recently got a raspberry Pi camera module. I really wanted to do stop animation with it but, when I used Tkinter to make a button it would take a picture when I pressed it and save it as I specified. The problem is if I wanted to use the button again it deleted the old image ex image.jpg and replaced it with a new image (image.jpg). Do you have any suggestions of how to change the code so it will name the photos numerically. Ex image1.jpg then image2.jpg. I'm doing all this in idle3. Thanks a lot for the book. "Python for kids" is great.

Glad you like the book.

There's a few ways you can change your code to have an incrementing filename. You could write a class, which uses a variable to store the current number. The class would have a function which increments the variable and returns the value. Something like this would work:

>>> class Counter:
...     def __init__(self):
...         self.counter = 0
...     def next(self):
...         self.counter += 1
...         return self.counter
...

You could use the class by creating an object like this:

>>> c = Counter()
>>> c.next()
1
>>> c.next()
2

You could then create a function to return a unique image name each time it's called:

c = Counter()

def get_image_name():
    return 'image%s.jpg' % c.next()

You could also just adapt the code above to create a class which returns unique image names:

>>> class ImageNames:
...     def __init__(self):
...         self.counter = 0
...     def next_image_name(self):
...         self.counter += 1
...         return 'image%s.jpg' % self.counter
... 
>>> im = ImageNames()
>>> im.next_image_name()
'image1.jpg'
>>> im.next_image_name()
'image2.jpg'

By the way, you can find more about embedding values in strings in Chapter 3, and classes and objects in Chapter in Chapter 8.

Hope that helps.


Well done Amazon - truly awful UX

22 Oct, 2014

How to ensure that your customers never, ever... ever want to sign up for Prime... ever:

Step 1.
Prompt user to sign up for Amazon Prime while processing their order.

Step 2.
Customer clicks "No Thanks" (because customer was previously signed up for Prime and decided they didn't want to pay for it - so of course you should ask again and again... and again)

Step 3.
Display final checkout page to customer and automatically select the paid shipping option (okay fine, that's fairly normal)

Step 4.
Display popup window to customer asking them to sign up for Amazon Prime again (did I mention again?), only this time position the Sign up link in the exact same position that that the radio button for "Free Super Saver Delivery" is displayed (because you know that's the button they're probably going to select). Better yet, you should time the display of this popup so that by the time they've moved the mouse cursor into place, customer is clicking on said radio button at the very moment the popup appears.

Step 5.
By no means should you ask for confirmation before signing the customer up, when they do mistakenly click.

Frankly, don't know whether it was just exceptionally poor, or whether it was nefarious UX design to get people on Prime, but it's a really, really good way to annoy your customers. Or at least this customer.


Multiple statements found

08 Sep, 2014

Arijjan V writes (excerpted):

When I enter code into the compiler I continue to get multiple statement error messages. Even if I copy the code from the book.

I use Idle 34 on windows professional 7. This is what I typed into the Idle Shell.

found_coins = 20
magic_coins = 70
stolen_coins = 3
coins = found_coins
for week in range(1, 53):
    coins = coins + magic_coins - stolen_coins
    print('Week %s = %s' % (week, coins))
**Click Enter**
SyntaxError: multiple statements found while compiling a single statement

I searched online but it's not an indent error. I'd appreciate any help.

To be honest, I'm not quite sure how you managed to get that error when typing the code into IDLE - the only way I can get it to happen, is if I copy-and-paste directly into the Shell:

Multiple statements showing error

The reason being is that you can only copy-and-paste line-by-line into the Shell window (a quirk of the way it works). What you should actually be entering looks like this:

Multiple statements without error

If you want to paste in a large chunk of code, then click File, then New File, then paste the code, and save the file before trying to run it:

Multiple statements in new file

If you can reproduce the problem when typing in the code, send a screenshot (take it after entering a few lines) -- I'd be interested to see if it's obvious from the screenshot what the cause is...


Restarting the game

29 Aug, 2014

Lyna M writes (excerpted):

I bought your book Python for Kids with the intention to teach my son Python later on but have now been using it myself to learn Python as I find your book to be quite comprehensive even if it was 'for kids'.

I've been doing the Bounce tutorial and would like to find a way to add a restart button so that each time the game ends, the player can restart the game if they want to.

I've applied the codes for Game Over but would like to add a restart button after that.

if ball.hit_bottom == True:
    time.sleep
    canvas.itemconfig(game_over_text, state='normal')
    btn = Button(tk, text="Click to Restart Game")
    btn.pack()
tk.update_idletasks()
tk.update()
time.sleep(0.01)

tk = Tk()
btn = Button(tk, text="Click to Restart Game")
btn.pack()

How to tie in the button so that it restarts the game when clicked? I've been trying out codes from forums and blogs but they don't seem to work or are too hard to understand.

There's a few ways you can handle the restart. If you look at the programming puzzles in Chapter 14, the first challenge is to delay the game start using the <Button-1> binding to tie a mouse button click to a function which starts the game. You could adapt that function to also restart the game once it's over. That's probably the most seamless approach.
If you really want to use a button, you need a way to add it just once -- because where you've added it (inside the loop), you'll get one button added to the window for every iteration of the loop. After the loop finishes isn't really the right place either.

First of all you'll need a Game class which will tie all the game objects together. Basically the new class would have object variables to 'store' the paddle, the ball, the score, the game-over-text, and also your restart button (initially the restart button variable would be set to None). So rather than adding the button inside the if-statement, you might do something like this:

    game = Game(canvas, paddle, ball, score, game_over_text)

        --- ✂ ---

    while 1:

            --- ✂ ---

        if ball.hit_bottom == True:
            time.sleep(1)
            canvas.itemconfig(game_over_text, state='normal')
            if game.restart_button is None:
                game.add_restart()

In the above code, if the game variable restart_button is None (not currently displayed), we call a function add_restart - so that fixes the problem of adding the button more than once. Here's the code for adding the button:

class Game:

        --- ✂ ---

    def add_restart(self):
        self.restart_button = Button(tk, text="Click to Restart Game", command=self.restart)
        self.restart_button.pack()

The command associated with the button is the function on our Game class called restart - this is the guy that takes care of hiding the game over text, putting the ball and paddle back in their starting positions, and so on.

Hope that helps somewhat.