Significant Whitespace

The first thing to notice is that the Python statements don't have line separators - no semi-colon at the end of each line.

This is a reflection of the fact that Python handles white space in a way that might be unfamiliar to C#/C++ programmers - significant whitespace.

Yes that's correct, the whitespace that you leave in a Python program means something. This goes much further than VB's use of whitespace and you need to know that while the start of a code block is marked by a colon the end is marked by indentation.

For example, Python has a fairly standard for statement:

for i in range(1,11): print iprint 'end of loop'

This prints the values 1 to 10 but notice that the block of code that is iterated starts with the colon and includes anything indented below the for.

The arguments for and against significant whitespace are many but at least there are no arguments about how Python should be laid out.

If you do it your own way then the chances are it won't work! Python has the usual range of control statements, while, if, etc, and the only real difference is the use of the colon to mark the start of a block and indenting to show where the block ends.

No typing

The key thing about dynamic languages is that they treat variable type in as flexible way as possible. You can generally assign anything to anything and hope it makes sense. Python always attempt to work out what type of data a variable is storing and match the operation to this.

This is often called "duck typing" from the old saying "if it looks like a duck, quacks like a duck, etc, then it is a duck".

If you have been schooled in strong typing and brought up on C++ or C# then duck typing will seem like an error waiting to happen and it is true. Strong typing was invented to try and make programming more error free, but it takes time and effort and dynamic or duck typing is quick and makes for efficient code generation.

To define a function you use the def command, complete with parameters if needed, and a return statement to return a value. For example:

def add(x,y): return x+yprint(add(1,2))

If you are using IronPython Visual Studio Tools you don't have to actually enter the tab to start the body of the function - the system does that for you. In fact you have to remember to remove the indent to mark the end of the function.

Notice that parameters are typeless and this is both a convenience and a possible problem.

For example, with the above definition of add the following works perfectly:

print(add('lumber','jack'))

and prints "lumberjack"

If you find this strange and worrying then it is perhaps because you have been in the grip of strongly typed languages for too long!

When you write the add function you are thinking about “adding” together two objects and it is up to the system to work out what you mean by “+” for any two objects you care to pass.

Notice that strongly typed languages such as C# have had to invent the idea of "generics" to allow the general concept of adding two things together to be used in methods irrespective of the exact type of the object passed to the method. If you aren't being too fussy about typing then generics come for free and quite naturally - the only problem is that you might write a function that does a little more than you ever intended. That is, if you only intended to write a function which adds to numbers together then you have more than you bargained for.

It even works for lists - in fact it works for any two objects that makes sense of the + operator:

print(add([1,2],[3,4]))

which prints[1, 2, 3, 4]

Notice that Python doesn't have arrays - the list seems to be enough for any purpose - but you can make use of .NET array objects.

Exactly how is our next subject.

One more complication is that we need to know the scope of a function or a variable definition.

The basic idea is that a name belongs to the namespace that is appropriate to where it is first used – local, global or built in.

If you want to make a variable name global from within a function you have to declare it as such using “global”. Arguments are also influenced by the “object” idea. These are passed into functions by assigning them to local names, i.e. the objects that are passed are simply given new references to them within the function. This results in a behaviour which many programmers will regard as strange.

For example suppose you write:

def test(a): a=1

Then when you use this function with a call like:

x=2test(x)

the value of x is unchanged by the assignment within the function.

Ah, you might say, this is pass by value, but not so. What is happening is that when the function is called the local variable “a” is set to “point” to the same object that “x” is “pointing” at. When the object 1 is assigned to “a” the variable “x” is still pointing at the object 2.

You might think that this is indeed pass by value but it isn’t because if you try:

def test(a): a[0]= “spam”x=[2,3,4]test(x)print x

you will discover that the list in the calling program, x, has its first item changed to “spam”.

What is going on here is, of course, that a reference to an object is being passed by value and any changes to the reference are ignored but any changes to the object are permanent. This is how most object oriented languages pass objects in functions but ... most don't regard a simple integer as an object as Python does.

There are also facilities for passing arguments by name, variable numbers of parameters and parameter defaults.

For functional programming enthusiasts Python has a lambda expression facility, which allows any expression to be treated essentially as a data object.