Learning Python: Object-Based Programming
By: Michael Mcmillan
Tags: Python Programming, Python Object, Object Oriented, Learn To Code, Objects

Photo by Oskar Yildiz on Unsplash

In this article and the next few I’m going to introduce you to object-oriented programming in Python. These articles will show you how to create your own user-defined data types that powerfully extend the usefulness of Python into any domain of your choosing. In this first article I’m going to demonstrate how to create simple objects in Python that can used as user-defined types.

What is an Object?

There is lots of confusion in programming about objects. I am going to define objects for my purposes as this: a user-defined data type that defines the attributes of the type and the behaviors of a type.

To use programming language you are already comfortable with, an attribute is a variable that describes some aspect of an object. For example, a person has a name, so name is an attribute of a person. A car has an engine, so engine is an attribute of a car.

A behavior is like a function that describes what an object does. A cat makes a sound, so sound is a behavior of cats. A point in two-dimensional space can move, so move is a behavior of a point.

When we write object-oriented programs in Python, we define objects that have attributes and behaviors and we wrap the attributes and behaviors into one package — the class. If we weren’t able to do this, we’d have to have individual variables for every attribute and every behavior and that quickly becomes unmanageable.

Creating Objects in Python

In this article, I’m not going to create fully-developed objects that include all the attributes and all the behaviors possible. Instead I’m going to start slowly by demonstrating how objects are created and how to define and access a few attributes of those objects.

Let’s start by defining a Point object or class. Before I do that, let me mention one aspect of object-oriented programming convention. When defining a new class the class name should start with a capital letter. This helps distinguish class objects from other things, such as variables.

Here is how I can define a Point class:

class Point:

"""Point represents an object in 2-D space"""

New class objects are defined with the keyword class followed by the class name (starting with a capital letter). The string that follows is called a docstring and it’s there to help someone recognize what a Point object represents. I could leave it out but it makes the class definition look weird.

I can create a Point object by a process called instantiation. It is called instantiation because it creates an instance of the class. For example:

pt1 = Point()

pt1 is an instance of the Point class and now can be used in the program.

A point has two attributes, an x-coordinate and a y-coordinate and I can create these by defining them like this:

pt1.x = 2.0

pt1.y = 3.0

The dot operator is used to specify the attributes of a class.

I can retrieve the attributes by calling them from the object, again using the dot operator to separate the instance name from the attribute:

print("pt1.x:",pt1.x,", pt1.y:",pt1.y)

Here is what I’ve done so far in a complete program:

class Point:

"""Point represents an object in 2-D space"""



pt1 = Point()

pt1.x = 2.0

pt1.y = 3.0 print("pt1.x:",pt1.x,", pt1.y:",pt1.y)

The output from this program is:

pt1 x: 2.0 , pt1 y: 3.0

For now, you cannot access the attributes of a class object in aggregate, such as by writing:

print(pt1)

Here is what I get when I try this in the Python shell:

>>> print(pt1)

<__main__.Point object at 0x00000145E8560AF0>

This is telling me there is a Point object at this memory address but Python won’t access the attributes. I have to access the attributes via the dot operator. In a later article I’ll show you how you can get this code to work but for now we need to look at other solutions.

One solution is to create a function for printing points. This solves our immediate problem but is not really a long-term solution. I’ll be discussing that solution in my next article.

With that said, here’s a function for printing the contents of a Point object and a test program that uses the function:

class Point:

"""Point represents an object in 2-D space""" def printPt(pt):

print("x:",pt.x,"y:",pt.y) pt1 = Point()

pt1.x = 3.0

pt1.y = 5.0

printPt(pt1)

The output from this program is:

x: 3.0 y: 5.0

This shows that our user-defined objects can be used as arguments to functions. User-defined objects can also be used as function return values. For example, let’s define a function that can find the midpoint between two points. Here is the function definition:

def midPoint(p1, p2):

p = Point()

p.x = (p1.x + p2.x)/2

p.y = (p1.y + p2.y)/2

return p

Here is a complete program that tests the function:

class Point:

"""Point represents an object in 2-D space""" def printPt(pt):

print("x:",pt.x,"y:",pt.y) def midPoint(p1, p2):

p = Point()

p.x = (p1.x + p2.x)/2

p.y = (p1.y + p2.y)/2

return p pt1 = Point()

pt1.x = 1

pt1.y = 3

pt2 = Point()

pt2.x = -3

pt2.y = 4

pt3 = Point()

pt3 = midPoint(pt1, pt2)

printPt(pt1)

printPt(pt2)

print("Midpoint:",end="")

printPt(pt3)

Here is the output from this program:

x: 1 y: 3

x: -3 y: 4

Midpoint: x: -1.0 y: 3.5

Python Objects are Mutable

You can change the attributes of an object by accessing the attribute in an assignment statement. For example:

p1 = Point()

p1.x = 1

p1.y = 2

printPt(p1)

p1.x = 4

printPt(p1)

The output of this program is:

x: 1 y: 2

x: 4 y: 2

Beware of Copying Objects

When you copy a class object using assignment, you create a shallow copy of the original object, sometimes also called an alias. What this means is that if you make changes to the original object, the copied object changes as well. Here’s an example:

class Point:

"""Point represents an object in 2-D space""" def printPt(pt):

print("x:",pt.x,"y:",pt.y) p1 = Point()

p1.x = 1

p1.y = 2

print("p1: ",end="")

printPt(p1)

p2 = p1

print("p2: ",end="")

printPt(p2)

p1.x = 2

print("p1: ",end="")

printPt(p1)

print("p2: ",end="")

printPt(p2)

The output from this program is:

p1: x: 1 y: 2

p2: x: 1 y: 2

p1: x: 2 y: 2

p2: x: 2 y: 2

I changed the x coordinate of p1 and when I did, the x coordinate for p2 changed also. This is because, internally, the p2 object is “pointing at” the p1 object, so any changes to p1 happen to p2 as well.

The solution to this problem is to use the copy module provided by Python. In the module is the copy function, which will make a deep copy of the object passed to it.

Here’s the example above rewritten with the copy function:

import copy class Point:

"""Point represents an object in 2-D space""" def printPt(pt):

print("x:",pt.x,"y:",pt.y) p1 = Point()

p1.x = 1

p1.y = 2

print("p1: ",end="")

printPt(p1)

p2 = copy.copy(p1)

print("p2: ",end="")

printPt(p2)

p1.x = 2

print("p1: ",end="")

printPt(p1)

print("p2: ",end="")

printPt(p2)

The output from this program is:

p1: x: 1 y: 2

p2: x: 1 y: 2

p1: x: 2 y: 2

p2: x: 1 y: 2

Now when I copy p1 and then change one or more of its attributes, the changes aren’t reflected in the p2 object.

That wraps up all I want to say about Python objects in this article. In my next article we’ll look at how functions can be moved inside a class definition so that there is a tighter coupling between class objects and the functions (which are called methods when defined inside a class) the objects use.

Thanks for reading. Please email me at mmmcmillan1@att.net with your comments and suggestions or respond below.