Getting Started with Python
Written by Mike James   
Thursday, 01 March 2018
Article Index
Getting Started with Python
Control Statements
Objects
Inheritance

Everything is an object - references

At the very start of this introduction to Python I said that it was an object-oriented language and you might well be wondering when the objects are going to make their appearance.

Well in a sense they already have. Python calls just about everything an object and this reflects the way the Python system treats everything equally.

This everything is an object idea has one very big consequence that it is worth getting sorted out at as early as possible.

In most programming languages you store values in variables.

In Python variables store references to objects.

You can think of a reference as a pointer to an object which exists independently of the variable.

For example, consider:

 x=1
 y=x
 y=2

In this case you might read this as store 1 in x, copy what is stored in x to y, now store 2 in y. At the end we have 1 in x and 2 in y.

So far everything works as you would expect, but this is not what is happening.

The correct interpretation is that x is set to reference the object 1, then y is set to reference the same object, and finally y is set to reference the new object 2.

In this case the result is the same, but this isn't always the case. Consider the same process but now with a list:

 x=[1,2,3]
 y=x
 y[0]="spam"

If you read this as the list [1,2,3] is stored in x, then the contents of x are stored in y and the first element of the list in y is changed to "spam" then you have to conclude the x[0] is still 1.

This is not the case as x is set to reference the object [1,2,3], then y is set to reference the same object, i.e. no copy is made, and finally y[0] is changed to "spam".

I hope now you can see that the first element of the object that x and y reference has been changed.

In Python variables hold references to objects.

Functions

In Python a function is a valid example of an object.

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+y
print(add(2,3))

As always the body of the function is determined by the indent. 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 displays

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.

Before you ask – yes it works for lists as well:

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

which prints:

[1, 2, 3, 4]

With untyped parameters you can pass anything you like to a function and what it does with the objects you pass depends on what they are. It is up to you to check that it makes sense.

In python every function is generic.

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 name space that is appropriate to where it is first used – local, global or built in.

So if a variables first use is in a function then it is local to that function.

Variables first used in a block are local to that block and you cannot use a variable's value until it has been initialized.

If you want to make a variable name global from within a function you have to declare it as such using “global” but this is generally not a good idea.

Notice that this is the opposite way most other languages handle the problem.

In Python variables are local unless you declare them to be global.

Arguments are also influenced by the everything is an object  idea and the fact that variables hold references and not values.

What this means is that when you pass something in a parameter it is a reference to an object that is passed.

In short all parameters are passed by value but what is passed is a reference to an object.

This results in a behavior 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=2
test(x)
print(x)

you will see 2 printed. The value of x is unchanged by the assignment within the function.

Ah, you might say, this is pass by value, but this isn't accurate.

What is happening is that when the function is called the local variable “a” is set to “point” to or to reference the same object that “x” is “pointing” at.Thus when a is accessed it returns 2.

When the 1 is assigned to “a” the variable it is treated as an object and a is simply set to point or reference the new object i.e. 1. The original variable is still pointing or referencing the original object i.e. “x” is still pointing at the object 2.

When you work with simple object like numbers then this does look like pass by value but as soon as you pass a more complex object it becomes clear that it is pass a reference by value or more properly pass by object reference:

def test(a) :
a[0]= "spam"

and use

x=[1,2,3]
test(x)
print(x)

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

The reason for the difference is that you have changed part of the object that both variables are pointing at.

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

Python also has a lambda expression facility, which allows any expression to be treated essentially as a data object and passed as s parameter to another function. The Python lambda is more like an anonymous function object than a true lambda.

There is much more to say about functions in Python but this is a good start.

An Object of My Own

Moving on to more traditional object-oriented facilities brings us to the class statement.

Python implements objects using the traditional mechanism of defining a class and then creating instances of the class. However it isn't quite the traditional kind that you find in say C++, Java or C#. It is more like the way objects work in JavaScript. The idea of a class in Python is once again influenced by the "everything is an object" idea. Yes a class is just an object but with some special features that enable you to use it to create a clone of the object - an instance.

You can define a class complete with instance properties and methods and use it by simply calling the class as if it was a function.

This sounds all too easy and I have to admit that it really is easy once you are aware of the slight differences.

One minor complication is that you have to use the variable self as a reference to the particular instance of the class within property and method declarations. You also need to group instance properties within a function called __init__ i.e. with two prefixed and trailing underscores.

If this all seems like an arbitrary set of rules then the good news is that it is very logical and understanding the deeper way it all works is well worth the effort - see the later chapter on class.

Consider, for example,

class point:
    def  __init__(self):
        self.position=(0,0)
    def setpos(self,x,y):
        self.position=(x,y)
    def display(self):
        print( self.position)

This defines a class called point which has one instance property position and two instance methods – setpos and display.

Each of these has self as its first parameter. This is automatically set to reference the instance  which is a reference to the current instance of the object created from from the class.

You can now create an instance of the class using:

a=point()

Notice that the brackets are all-important – without them you create variables pointing to the class, not the instance. This is a big difference between Python and other object-oriented languages - the class is actually an object that is created on an almost equal footing with its instances. .

You can refer to methods using the usual dot a.method() notation.

For example,

a.setpos(1,2)

and

a.display()

When you call a method, like

a.setpos(1,2)

the self parameter is automatically set to the instance, a in this case. Thus the method call is transformed into:

setpos(a,1,2)

In fact all method calls are translated from:

instance.method(parameters)

to

class.method(instance,parameters)

and the first parameter is the self you include in every method definition.

You can even call instance methods directly using this form. For example,

point.setpos(x,1,2)

is entirely equivalent to

x.setpos(1,2)

and of course this is the trick Python uses to implement object instances. Any method call on an instance is converted into a call onto the function hosted by the corresponding class object.

Python uses an approach to objects that is very similar to that used by JavaScript and the two languages have a lot in common.



Last Updated ( Friday, 13 November 2020 )