Introduction To Programming In Python

Image credit: Chris Ried

This is the second article in a series designed to introduce beginners to programming in various popular languages. In my last article, I covered JavaScript. Those who read the last article may notice a similar structure, but plenty of new Python content is available for you to sink your teeth into!

Python 3

Python has two versions to worry about. Python 2 was the first language I ever programmed in, when I was around 10. I was learning it all from a hefty book which proved to be a less-than-ideal start to my programming journey! Make sure that you are using Python 3, as Python 2 is being deprecated so we won’t be learning about it here. However, there are still many tutorials out there in the old version, so watch for the differences.

Python is a scripting language that employs dynamic duck typing (if it looks like a duck, it’s probably a duck). It is is great if you want to easily automate the monotonous tasks in your computing life! It’s basically BASH for beginners!

Many would argue that Python is a great programming language for beginners. I disagree with this statement, mainly due to the syntax of Python being simple. Why is this an issue? Simply put, when a language is structured to be overly simple, it can prove to be a poor teaching tool by abstracting away many things that new Computer Scientists should be familiar with, such as data types and fixed-size arrays. However, if your goal is just to build stuff quickly, and you don’t really care so much about learning how it all works under the bonnet, Python is quite handy. I would particularly recommend it for writing useful scripts and data science, particularly for students or practitioners in the natural or social sciences.

Getting Started

In order to get going with Python, you need to install an interpreter on your system, so that the script files can be executed. It’s not too difficult to do this, and you can follow along using the official Python website. Python should already be installed on macOS (but may need updating). On Ubuntu (Linux) you may have to install with sudo apt install -y python3. On Windows, you can download the installer from the website. Ensure you are running the latest Python 3.

Everything we do can be run in the IDLE console, which can be launched with the terminal command python on macOS or Linux, or by running Python IDLE on Windows. You will get a prompt appear, and you can start typing Python code:

Python 3.8.3 (default, May 17 2020, 18:15:42) 
[GCC 10.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

Try doing some mathematics! Something like 2 * 3 will be evaluated once you press the return key. The value that is returned from the expression will be output below the console prompt. Now we’re coding!

(If you have any issues with your install, check out the Beginner’s Guide)

Hello World!

Originally attributed to Brian Kernighan (one of the creators of the “C” language) when he worked at Bell Labs, pretty much every programmer starts off with this infamous program1. In almost every language, this is how you output the state of your program, letting you see what’s going on “under the bonnet” so you can fix bugs.

Write the following in your IDLE console:

print("hello, world")

Great! You’ve just written some code. It doesn’t do much, but everyone has to start somewhere! Let’s unpack it.

You are called the print() function, which is provided by the Python Standard Library, allowing you to easily output stuff for your users or for debugging. You pass it a text string as a parameter, such as "hello, world".

Once you hit the return key, you should see the text output by the function in the Python console. How it actually does this doesn’t matter, but it essentially runs code that someone else wrote.


Comments are really handy. We use them to leave notes to describe what code is meant to do, explaining our intentions to other programmers and our future self! Some code is pretty self explanatory (2 + 3), but sometimes you want some explanation. Comments are simply ignored by the Python interpreter.

Try these out:

# Single line comment
# Another comment

# print("Not going to run...")

If you’ve done everything right… nothing will happen. Well done.

Note that if you hit return, your code will be executed as long as the line is valid. For example, if you type something like print("test"), the code will be evaluated straight away, but if you typed something like print(, you will be required to close the bracket ()), finishing the statement before it is executed.



You may recognise some of these from maths! The best way to see how these work is to try them out:

x + yAdd both numbers
x - ySubtract y from x
x * yMultiply both numbers
x ** yRaise x to the power of y
x / yDivide x by y, without rounding
x // yDivide x by y, rounding down to an integer
x % yThe remainder of dividing x by y

Note that order of operations (BIDMAS, BODMAS, etc.) applies in programming too if you want to chain operations.

Multiplication and division may look a little weird, but you’ll get used to it after a while! The strange one is probably modulo (%). Try doing 7 % 3. The number 7 has two 3s in it (2 * 3 = 6), with a remainder of 1. You can do this division with 7 / 3 (2.3333333333333335), and round down the result with round(7/3) (another method). As you get more experienced, you’ll find more practical uses of this operator, but don’t worry now if it’s confusing.

In Python, you also have the additional operators ** and //.

  • ** is used for powers, such as 32, which would be written 3 ** 2
  • // is used for division, but rounds the result (the counterpart of modulo). Any division would work with this, just as with the / operator.


Next up are the comparison operators. Aptly named, they let you compare two values! They return True if a match is found, or False if not:

x < yReturns True if x is less than y
x > yReturns True if x is greater than y
x <= yReturns True if x is less than or equal to y
x >= yReturns True if x is less than or equal to y
x == yReturns True if their value and type are equal
x != yReturns True if their value and type are not equal

One difference you will notice is that we don’t use the normal mathematical symbols (≠, ≤ or ≥). This is probably a great relief, I highly doubt you have any of these characters on your keyboard! We also use the weird == sign. What does this mean? Super equals? As you’ll see, = is the assignment operator, so we use == for equals.


Last but not least are the boolean operators. They allow combination of boolean expressions that are either true or false. Named after English Mathematician, George Boole 2, who came up with much of the logical mathematics that we use in computers today, long before they were even invented! That’s one smart cookie!

These operations boil down to and, or) and not, which allow you to chain together True or False logical statements, such as 2 < 3 (True) or 234 == 92 (False).

TrueAlways true
FalseAlways false
A and BTrue if both A and B are true
A or BTrue if either A or B are true
not AThe opposite of A


Right, now we need to think about storing stuff. We’ve been manipulating values and seeing the result of this, but it would be handy to store the result for later. For this, we need variables.

We learnt earlier that JavaScript is a dynamically (duck) typed language, but what is a type, and what is this “dynamic” business about? Computers need to know the type of thing stored - is it a number, is it string of text, and so on. You can figure out the type of a value or variable using the type() function. If you want to check for a particular type, use the is keyword (type(3) is int), which returns a boolean value. There are four primitive data types in Python. Primitive types are the simplest forms of data representation, used to represent singular values, instead of a collection of values.:

int37, -9, 0
float3.14, -2.47, 0.00
str“hello”, ‘hi’, “a”
boolTrue, False

You can read more about the Python data types here:

Let’s create some variables:

myvar = "hello"

a_bool = False
an_int = 37
a_float = 3.14

type(an_int)        # <class 'int'>
type(an_int) == int # True
type(an_int) is int # True

Note that unlike most other languages, Python does not have constants in the normal sense. However, using a naming convention such as snake_case for variables and MACRO_CASE for constants should help to assert how such variables should be used.

The following article is really useful for explaining variables:


Making decisions is an important function of any computer. We should be able to branch into alternative code pathways, and execute different code in different conditions (described by boolean expressions.)

The simplest decision is whether or not to run a block of code. For this, we use an if statement, which executes a block of code if a certain condition is true:

graph TD b(Start) b --> condition{age == 18} -- True --> action[Output some text] --> e(Stop) condition -- False --> e style b fill:forestgreen,stroke:#333,color:#FFF style e fill:firebrick,stroke:#333,color:#FFF style condition fill:palegoldenrod,stroke:#333 style action fill:lightgray,stroke:#333

Let’s take a look at the code:

if age == 18:
    print("Congrats! You're now an adult.")

Sometimes we want to do something when the condition is not true - an “else” condition:

graph TD b(Start) --> condition{age == 18} -- True --> action["Congrats! You're now an adult."] --> e(Stop) condition -- False --> action2["You aren't 18."] --> e style b fill:forestgreen,stroke:#333,color:#FFF style e fill:firebrick,stroke:#333,color:#FFF style condition fill:palegoldenrod,stroke:#333 style action fill:lightgray,stroke:#333 style action2 fill:lightgray,stroke:#333

And in code:

if age == 18:
    print("Congrats! You're now an adult.")
    print("You aren't 18.")

And, sometimes you want to check another condition if the first was false.

graph TD b(Start) --> condition{age == 18} -- True --> action["Congrats! You're now an adult."] --> e(Stop) condition -- False --> condition2{age < 0} condition2 -- True --> action2["You aren't born yet!"] --> e condition2 -- False --> action3["You aren't 18 and you're alive. Well done."] action3 --> e style b fill:forestgreen,stroke:#333,color:#FFF style e fill:firebrick,stroke:#333,color:#FFF style condition fill:palegoldenrod,stroke:#333 style condition2 fill:palegoldenrod,stroke:#333 style action fill:lightgray,stroke:#333 style action2 fill:lightgray,stroke:#333 style action3 fill:lightgray,stroke:#333

This is where if else comes in:

if age == 18:
    print("Congrats! You're now an adult.")
elif age < 0:
    print("You aren't born yet!")
    print("You aren't 18 and you're alive. Well done.")

Nice! We can now write conditional code. You’ll be a pro in no time!

If you fancy another explanation and few more examples, check out


Sometimes we want to repeat ourselves. Let’s say we wanted to output “Hello, " and your name 10 times. Is this how we’d do it?

print("Hello, Tim")
print("Hello, Tim")
print("Hello, Tim")
print("Hello, Tim")
print("Hello, Tim")
print("Hello, Tim")
print("Hello, Tim")
print("Hello, Tim")
print("Hello, Tim")
print("Hello, Tim")

Probably not. It’s quite messy, takes up a bunch of space, and is not very maintainable (imagine changing the name!)

A good thing to remember as you learn is to write DRY code (Don’t Repeat Yourself) 3. Repeated code is a good sign that there’s a better way. Avoid WET, repeated code (Write Everything Twice). Let’s refactor our code to make it less repetitive, by adding a variable to store the name, and using a while loop:

name = "Tim"
i = 0
while i < 10:
    print("Hello, " + name) # The + operator concatenates strings
    i += 1

If you run this, you’ll see that we get the same result, but our code looks a great deal better. We have a variable, name, and a while loop.

The loop is likely new to you, so let’s unpack it. Essentially, the loop will repeat while the condition is True:

graph LR b(Start) --> action1[i = 0] --> condition{i < 10} -- True --> action2[Hello, Tim] --> action3[i++] --> condition condition -- False --> e(Stop) style b fill:forestgreen,stroke:#333,color:#FFF style e fill:firebrick,stroke:#333,color:#FFF style condition fill:palegoldenrod,stroke:#333 style action1 fill:lightgray,stroke:#333 style action2 fill:lightgray,stroke:#333 style action3 fill:lightgray,stroke:#333

There are three important parts to our loop:

  • i = 0 - Creates an iterator variable called i (you can call it whatever you wish) and sets it to 0
  • i < 10 - The boolean expression (condition) evaluated each loop iteration
  • i += 1 - Really important! Without this, i will remain the same, and our loop will go on forever (an infinite loop)
    • i += 1 is shorthand for writing i = i + 1
    • It adds one to i, then stores the result back into the variable

Another type of loop is the for loop, which is more concise:

for i in range(5):
    print("I'm number", i)

Note that comma-separated arguments to print() are separated by a space in the output.

The code above should output:

I'm number 0
I'm number 1
I'm number 2
I'm number 3
I'm number 4

The for loop in Python is a bit different to other languages, as it is used to iterate over sequences such as lists.

for <iterator> in <sequence>)
  • <iterator> is just a variable, which can have any valid name. It represents the current item in the sequence.
  • <sequence> is any valid sequence, including lists, tuples, dictionaries, sets, or strings.
    • We’ll learn more about them later on.
  • The range function returns a list of numbers that can be iterated over. In our example, range(5) produces the list [0, 1, 2, 3, 4].

You can use the enumerate function if you need a numbered sequence:

fruit = ["apple", "cherry", "orange"]
for i, thing in enumerate(fruit):
    print(i, thing)
0 apple
1 cherry
2 orange

You can read more about loops here:

Example: Guessing Game

You’ve learned enough that you can create your own text-based game! How cool is that‽

First, we need to create a file. While the console is great for learning and testing stuff out, it’s a bit annoying for anything permanent. Instead, you can create a Python file with any plain text editor. Note that the “plain” bit is important - don’t create code in a word processor, as these programs add a bunch of other stuff into files that we don’t want!

You could use something like Notepad on Windows, TextEdit on macOS or GNOME Text Editor on Linux, but these programs aren’t really designed for writing code. Instead, you’ll want to use something like Sublime Text, Atom, or Visual Studio Code (what I’m using to write this!) All of these programs are free, so check them out and see what you think! There are also more advanced Integrated Development Environments (IDEs) available, but we won’t concern ourselves with them.

Create a file with the .py extension, such as “”. You can add a print() in the file to check everything is working. You can run these files in the Python interpreter, by passing the file name to the interpreter on the command line:


On Windows, you may need to use py instead in a command prompt window.

If you skip ahead, you can find my full solution, but you will gain little knowledge by just copying it. Programming is about problem solving, a skill that only comes with practice. But, you need a couple of building blocks to solve this problem, most of which you already have, but there two additional things you need.

Building Block #1

import random
number = random.randint(1, 10)

Before you start, you need to generate a random number. For this, we can use the randint function. Note that the result is not actually random 4, but it’s good enough for us. We want a random number between 1 and 10, so we pass that upper and lower bound as arguments to the function. In order to gain access to this function, we need to import the random library by placing import random at the top of the file.

You can learn more about the randint function here:

How did I work this out? I searched the internet. There is nothing wrong with using Google, DuckDuckGo, Bing, or whatever your wish to look stuff up. Developers don’t need the best memories, and use search engines all the time! You can do this if you ever get stuck :)

Building Block #2

guessInput = input("Take a guess!")
guess = int(guessInput)

The second thing you need to know is how to get player input. We get user input as a string, then convert it to a number, stored in the guess variable. Note you could do this in one line, by nesting the input() inside the call to int(). Note that a ValueError will occur if the string input cannot be converted to an integer.

You now have all you need to write the program - conditionals, loops, random numbers and user input. Give it a shot then we’ll discuss a possible solution. Remember that one problem can have many solutions, some better than others.

If you need some help getting started, look at my algorithm below. It is represented as pseudo-code (code not in any particular language.) Once you have this, it’s easier to translate the idea into a concrete program.

while <player has guesses left>
    guess = <player input>

    if guess is correct
        tell player
    if guess is too high
        tell player
    if guess is too low
        tell player


Okay, let’s look at my solution:

import random

number = random.randint(1, 10)
guesses = 0

while guesses < MAX_GUESSES:
    guess = input("Guess my number between 1 and 10")

    if int(guess) == number:
        print("You guessed correctly!")
    elif guess > number:
        print("Too high!")
        print("Too low!")

    guesses += 1

It’s not the best solution, and you will likely have come up with something a little different. There is a limit to the number of guesses (MAX_GUESSES), but you could also allow infinite guesses, exiting only when the user’s guess is correct.


You’ve written your first program, and hopefully you understand you need only a few building blocks to assemble some great code. That’s what functions are - building blocks of code that you can reuse. Some take parameters when called to yield different results each time.

Head back to your Python console or stay with the file, and follow along!

To clear up the terminology, a function looks like this:

def my_func():
    # Some code that does something
    print("I'm calling this print function inside my function!")

def another_func():
    pass # Does nothing

If you run the above code, nothing will happen. That’s because these are function definitions, and no code is actually executed. We create two new functions: my_func and another_func, then define its behaviour within its block.

We can call our function with its name, running the code defined above:


This function call can be treated like any statement. It can be nested inside a conditional, a loop, or another function.

Functions can also take parameters and return values. The function definitions above do not return values (by default, they return None, representing nothing.)

def add(num1, num2):
    sum = num1 + num2
    return sum

result = add(3, 4)

No prizes for guessing what this does. We take two parameters and return their sum.

num1 and num2 are formal parameters, which are replaced by the actual parameters (3 and 4) in the function call. This is really useful, as we can call the same block of code many times with different parameters.

Most of the time, functions can be copied between programs so you can reuse them in future projects. Third-party libraries are also available which provide useful functions written by others that you can use in your own projects. Python provides many additional functions in its standard library that can be imported using an import statement.

Go ahead and build some of your own functions to see what you can come up with. Here’s another example, but you can put pretty much anything inside a function:

def hello(fname):
    return "Hello, " + fname

hello("Tim") # 'Hello, Tim'

In Python, you can also provides default arguments, so they don’t always have to be explicitly stated. Just use = when defining your function:

def power(num, pwr = 2):
    return num ** pwr

power(3, 2) # 9
power(3, 3) # 27
power(3)    # 9


The “scope” of a variable refers to the block of code (indicated by indentation in python) where a variable exists. This could be a single function, file, or an entire codebase. Variables accessible everywhere in your code are usually called globals, and are either declared outside of a function (where any code after their declaration can access them.)

x = 2     # Create a new variable

def test():
    x = 3 # Create a new, separate x variable
    y = 2 # Create a new variable
    print(x) # 3
    print(y) # 2

print(x) # 2
print(y) # NameError: name 'y' is not defined

Global variables are usually avoided where possible, as anyone with access to our code can change them, which may effect other bits of our program. Often, we begin our Python code by calling a “main” function that keeps all of our variables confined to the local scope of our functions:

def main():
    # Do some stuff


The concept of scope can be complicated. Luckily, you don’t need to understand much about it when you start out! If you want to learn more, there are many explanations of the concept:

Non-primitive Data Structures

Python includes a number of non-primitive types which can be used for storing collections of primitive data types. I will discuss four important non-primitive types, including the list and tuple sequence types, set type and dict key, value mapping.


List are an ordered collection of items. You can access their contents using subscript syntax (a[3]), using a numeric index in the square brackets, starting from 0:

a = [2, 4, -3, 32, 11, -354]

# Retrieve item
a[2] # -3

# Replace item
a[0] = 37

print(a) # [37, 4, -3, 32, 11, -354]

Remember that an index of 0 indicates we’re looking at the first item!

Here are some useful methods (functions called on an object) you can call on lists:

# Add an item to the end

# Remove an item

# Get the length
len(a) # 6

You can use a for loop to easily iterate through all the items in an list, as we discussed above:

for num in a:

You can find out more about lists here:


Tuples are an immutable ordered collection of items, meaning you cannot modify their contents. You access individual items with subscript syntax, just as with lists. You declare them using round brackets:

a = (2, 4, -3, 32, 11, -354)

# Retrieve item
a[2] # -3

# You cannot change or add items
#   a[0] = 37
#   a.append(76)

# You can convert to a list though:
a = list(a)
a[0] = 37
a = tuple(a)

You can unpack individual values from a tuple with fancy declaration statement:

a, b, c = (1, 2, 3)
print(a) # 1
print(b) # 2
print(c) # 3

And we can use tuple unpacking to return multiple values from a function:

def get_multiple(name):
    return name, len(name)

n, l = get_multiple("Tim")
print(n) # Tim
print(l) # 3

You can find out more about tuples here:


Sets are an unordered, non-indexed collection of unique items. They are declared using curly brackets:

my_set = {3, 5, 7, 9}

# Print items in set
for x in my_set:

# Check if item exists in the set
5 in my_set # True
2 in my_set # False

# Add item

You can find out more about sets here:


Dictionaries in Python are unordered collections of key, value pairs. They are created with curly brackets:

my_dict = {
    "name": "Fred",
    "age": 30,
    "gender": "male"

# Check if key exists
"name" in my_dict # True
"blah" in my_dict # False

# You can access values using the key
my_dict["name"] # Fred

You can use a for loop to iterate over a dictionary:

for key in my_dict:
    print("key:", key, "value:", my_dict[key])

# Or using .items():
for key, val in my_dict.items():
    print(key, val)

Python provides the setdefault()5 method if you wish to ensure a particular key always has a value. It inserts the default value passed if one is not present already:

person1 = {
    "fname": "John",
    "lname": "Williams"
person1.setdefault("lname", "Smith")
print(person1) # {'fname': 'John', 'lname': 'Williams'}

person2 = {
    "fname": "John"
person2.setdefault("lname", "Smith")
print(person2) # {'fname': 'John', 'lname': 'Smith'}

You can find out more about dictionaries here:

List Comprehension

We learnt about loops earlier, but Python also provides a handy way of quickly assembling sequences called list comprehensions. If you wanted to construct a new list from another, you could do something like this:

old_list = [2, 4, 6, 8, 10]

new_list = []
for num in old_list:
    new_list.append(num ** 2)


But that’s not great. The syntax is very verbose, and the loop is also passed through the interpreter, line-by-line, which is not great for efficiency. Instead, you can use the more concise list comprehension syntax to create the new list:

old_list = [2, 4, 6, 8, 10]

new_list = [num ** 2 for num in old_list]

This is also more efficient, as the comprehension is handed over to the C backend to process quickly, rather than interpreting the code one line at a time.


Some final key tips for debugging programs, if you have issues:

  • Use print() to output the state of variables or the result of expressions - is that what you expected?
  • Use rubber duck debugging! Explain your problem to an inanimate object (like a rubber duck, fluffy toy, or your friend). This is often surprisingly helpful!
  • Check you have properly indented blocks of code inside functions, if statements and loops. Is the code you hope to run inside that block properly indented? If it seems to be, check you are consistently indenting (usually with 4 spaces per indent.) Most text editors and IDEs for Python will automatically convert tabs to 4 spaces on your behalf.
  • Make sure you use = for variable assignments and == for comparisons

The Zen of Python

Too often, we give new programmers these simple building blocks and then leave them to work on building good code themselves. While the experience is the best teacher, it is worth going into Python with some principles that will help you produce better code. The Zen of Python6 provides 19 aphorisms that provide some guidance when you are trying to write good code in Python, but some of these principles could apply to any language.

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!


Hopefully now you feel comfortable with the building blocks, and can start creating some simple programs using Python. Check out the W3Schools tutorial linked below to learn more about Python, including more advanced topics like packages, threading and object-oriented programming. I look forward to seeing what you make!

Any corrections or comments are always very much welcome!

Extra Reading

Timothy Clark
Timothy Clark
Software Engineer

Software Engineer with interests in cyber security and computing education.

comments powered by Disqus