My initial reaction was "where are the braces?".
Horror of horrors, it didn't have any block delimiters. Code blocks
were defined based on indentation! Yikes. I immediately returned
to my C++/Perl/awk and vowed never to look at this toy again.

No matter how hard I tried though, I stumbled on it, again and again.
An alarmingly large number of programs were being written with it...
and to my bewilderment, whenever I chanced a look at Python code,
I figured things out effortlessly, quickly -
and I didn't speak the language! The first time this happened
I attributed it to the competence of the programmer and the nice comments
he had written. The second time there were no comments - and yet I figured things
out just as easily. The third time, I googled for Python and stumbled on
Eric Raymond's "Why Python".

That was it. One of the high priests
was raving about this language - just like me, he had also been bitten by
the indentation fright but had gotten over it, and persisted to quickly
realize that this was a true gem. I followed suit.

4 years later, I am writing Perl only for quick'n'dirty text-processing,
the...

process data | perl -ne 'm/([a-z]*) goo/ && print $1;'

...kind.
Anything bigger, it's a no brainer: if it's going to be a script, it's in Python.
Incredible effort to gain ratio - compared to any other language I've used.
Notorious ease of learning; I have only read the tutorial over a weekend,
and that never got in the way of writing really large scripts. In fact,
for enthusiasts like me, that can be a problem! It is so easy to write
in Python, that I get carried away - I end up writing really large scripts
before I know it... I then have to stop and FORCE myself to refrain
from writing code and to plan it out first!

So where's the puzzle? you ask.

This year's "lab rat" is Lisp. I read the gospels of
Paul Graham and decided to
check this language out - the high priests seem to agree that this is the be-all
and end-all of computer languages. I'm almost there myself, having written just
a couple of Lisp macro's and been thoroughly impressed by the "code is data, let your
code do the coding" revelation. Lisp isn't Python, you need a good book and a lot
of effort to understand it,
so I'm reading Paul's "ANSI Common Lisp". On page 52, I ended up on an old acquaintance,
the "find the shortest path in a graph" problem. I vaguely remembered having met
it 14 years ago, in the university exercises...
Before attempting to think of it in Lisp, I smirked to myself: "How much time would
it take me to think up a recursive algorithm and write it in Python?". And
20 minutes later I had this:

Resist the temptation to skip the code - have a look at it. It's a simple, nice,
recursive implementation: in order to compare alternate paths, use recursion to find
the paths and costs from the neighbours to the target, and then check the costs
from the source to each of the neighbours. When you identify the best path,
return it to the caller via the 'shortestPath' function argument (points 1 and 2).

Er... it didn't work.

When I sprinkled the code with debug printing of the paths, it turned out that
the resulting paths in (1)
and (2) were not propagated to the callers. Why? I was passing mutable arguments,
plain old lists, they ought to have been changed! I checked some other scripts
I had written, and I was doing similar things there (sure enough) passing lists
as arguments to functions, modifying them and returning them to the caller.

That was a first - the obvious thing appeared not to work (until then, Python
had been 100% successful in reading my mind and doing whatever I desired).

With Python, when you are in doubt,
you never look at the manual - you fire up the interpreter and try things to make
sure you got it right (it's so much easier than reading manuals). Well, it was
working! (see below):

The function indeed changed the list I was passing in, why didn't it work in the
shortest path code?

I looked, and looked, and huffed and puffed - to no avail. I tried various alternatives
(the most hideous one was using a global list to pass the returned results back to the
callers - I almost choked from disgust and removed it immediately). What was happening?

Ah, the joy of programming.

It took me a while to notice that the test I did was not doing exactly what the
shortest path code did. When I tried it in the same form...

... it failed, just like the shortest path code! At least the thing was reproducible.
Obviously something else was happening - if the x=[2] assignment didn't change
the passed-in data, what was it changing?

At that point I decided to bite the bullet and have a look at the language docs. After
a fair amount of searching I got to this part:
"The execution of a function introduces a new symbol table used for the local variables
of the function. More precisely, all variable assignments in a function store the value
in the local symbol table; whereas variable references first look in the local symbol
table, then in the global symbol table, and then in the table of built-in names.
The actual parameters (arguments) to a function call are introduced in the local symbol
table of the called function when it is called; thus, arguments are passed using call
by value (where the value is always an object reference, not the value of the object).
When a function calls another function, a new local symbol table is created for that
call."

There was the answer to the mystery - inside the tutorial, by Guido himself.
Assignments are handled in a - special - way. In the first test I did, I was "referring"
to the passed-in argument, and invoking the 'x[1]' accessor to get to one of its data.
In the second test, I am assigning - and as Guido says, assignments store the value
in the local symbol table!

The problem probably only exists in the mindsets of C++ programmers - when I originally
read that paragraph of the tutorial, what I understood was the last part: that the value
passed in is always an object reference. In the C++ world, this is equivalent to:

returnType functionName(argumentType& arg)
{
}

...which in my mind meant, that if I do anything on arg, the caller will see the changes
in the data. Not so, in Python: all variable assignments in a function store the value
in the local symbol table. It is more like this C/C++ code:

returnType functionName(argumentType* arg)
{
}

...so by assigning to arg (arg = "foo";) you won't be changing the data passed in; the caller will never see the change, because the assignment is simply re-assigning the local symbol.

So how do I pass the results back to the caller?

I need to somehow "refer" to the variable, but I want to assign data to it... In a moment
of inspiration, I tried:

From A to G
From C to G
From E to G
From H to G
From G to G
FindShortestPath from H to G has cost 3 for ['H', 'G']
FindShortestPath from E to G has cost 10 for ['E', 'H', 'G']
From D to G
From H to G
From G to G
FindShortestPath from H to G has cost 3 for ['H', 'G']
FindShortestPath from D to G has cost 4 for ['D', 'H', 'G']
From F to G
From G to G
FindShortestPath from F to G has cost 1 for ['F', 'G']
FindShortestPath from C to G has cost 5 for ['C', 'D', 'H', 'G']
From B to G
From D to G
From H to G
From G to G
FindShortestPath from H to G has cost 3 for ['H', 'G']
FindShortestPath from D to G has cost 4 for ['D', 'H', 'G']
FindShortestPath from B to G has cost 6 for ['B', 'D', 'H', 'G']
FindShortestPath from A to G has cost 9 for ['A', 'C', 'D', 'H', 'G']
Best path is ['A', 'C', 'D', 'H', 'G']

Yes, it happens a lot with Python - things
tend to work on the first or second attempt. When they don't, it's because I'm lazy and
expect to use a language without properly reading a manual! Shame, coder, shame.

The comments on this website require the use of JavaScript. Perhaps your browser isn't
JavaScript capable or the script is not being run for another reason. If you're
interested in reading the comments or leaving a comment behind please try again with a
different browser or from a different connection.