The bulk of the content I plan on including in this site has to do with helping less experienced programmers in my class familiarise themselves with programming tools, practices and environments that are more common and useful outside of an academic [or, at least, undergraduate] environment. Python is a simple and powerful programming language that sees a lot of use in professional, casual and open-source spaces, and knowing it can make you more employable but can also help you make your life easier or participate in open source projects that interest you.

The objective of this guide is to help a student whose only exposure to programming so far was an AP Computer Science A (or equivalent, e.g. Introductory Computer Science in most universities) course, in which Java was the language of instruction, get familiar with Python and its syntax. This is not a comprehensive language guide. Instead, it includes some useful information as well as some syntax comparisons. I would appreciate comments regarding the extent to which this guide is helpful and ways in which you feel it might be improved.

Before Beginning …

NOTE: This section includes some information I think will help beginners convince themselves that learning another programming language, particularly Python, is worth their time. If you are convinced, feel free to skip this section.

Why a New Language?

After anywhere between a semester and a full academic year of writing Java in Eclipse or whichever programming environment your professor introduced you to, the thought of learning new languages and new tools can seem intimidating, unnecessary and tiring among other things. Is it worth it?

The answer, for a few reasons, is almost certainly.

One important thing to consider (that you might not be aware of if your only exposure to programming languages is Java) is that the vast majority of programming languages are syntactically and ideologically similar to one another. This is not an exaggeration designed to trick you into wasting your time, but rather a widely acknowledged fact. Now that you have learned and become reasonably comfortable with one object-oriented programming language, many others will come very easily to you.

There is, in my strong opinion, an even greater reason to learn a language and environment other than those to which you were introduced in high school or your first semester CS course, however:

The language and tools you were introduced to when you were beginning to program suck. They’re either bad, or really, really bad. Sometimes this is because of old conventions hanging around in “modern” computer science curricula. Other times, your professors intentionally ask you to use inconvenient tools because they are preparing you for an inconvenient exam.

Programming isn’t meant to be inconvenient, though, and forcing yourself to suffer inconvenience will not make you a better programmer. Renowned programmer Larry Wall, creator of the Perl language and the patch unix utility, outlines three virtues that any programmer should have:

  1. Laziness: The quality that makes you go to great effort to reduce overall energy expenditure. It makes you write labor-saving programs that other people will find useful and document what you wrote so you don’t have to answer so many questions about it.
  2. Impatience: The anger you feel when the computer is being lazy. This makes you write programs that don’t just react to your needs, but actually anticipate them. Or at least pretend to.
  3. Hubris: The quality that makes you write (and maintain) programs that other people won’t want to say bad things about.

The Java programming language has fallen behind its competitors in terms of design and features that make it convenient to use, the reason being that throughout its history, Java has been held back by the needs and demands of massive corporate entities, including hospitals, banks, pharmaceutical companies, etc.

Corporations whose interests are not in cutting-edge software or software development, but rather the opposite. Corporations who fear innovation, as innovation may bring with it breaking changes to their applications, which in turn bring major losses in profit. These corporations, for the longest time, have been Java’s primary investors, in turn rewarding Oracle for ensuring that the language did not change too much over the years, and instead stayed relatively the same for as long as possible.

Many programming languages that are maintained by the open source community, and even those that are maintained and developed by competitors of Oracle, have left Java in the dust, even though Java has made meager attempts to catch up in recent years. Languages like C#, Python, Ruby, and JavaScript among others have gained popularity while also becoming more and more convenient for programmers to use every year.

As you explore the programming landscape online, you will find that while Java continues to be a “popular” language, this is mostly so due to its heavy academic and corporate usage. In reality, Java is becoming less and less popular as the language of choice for programmers who are given one. Many of the open source projects you will discover on the internet are written in more convenient languages, and Python is among the most popular of them. That’s not to say, however, that it is seeing neglect or lack of use in professional spaces. As of 2019, Python ranks above Java in terms of popularity among professional developers in Stack Overflow’s annual developer surveys, and is second only to JavaScript.

There are infinitely more reasons to familiarise yourself with and even master the Python programming language, but you are sure to find them more gracefully articulated elsewhere on the internet. Hopefully this amount will do to convince you that the rest of this guide will be worth your time.

Syntax Comparisons

Note on environment: there is no need to install an entire development environment and tool-chain for this short tutorial. Instead you can use repl.it, an online platform for writing, running, and sharing code.

Hello World

The most basic Python program is shown here:

print("Hello World")

By comparison, the most “basic” Java program, one which does the very same thing as this single-line Python program, is a lot longer:

class Main {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

Closer inspection of the two samples will yield more noteworthy details. For example, notice that Python does not require that you end statements in semicolons as does Java. Furthermore, there is no need in Python to create a “Main” class or a “main” method. The code that is in a Python file is run as is. Although Python is an object-oriented language, it is entirely possible to write Python code that does not make use of classes.

Data and Types

In Java you were introduced to several different data types which stored different categories of information and occasionally had to be treated differently. For example:

class Main {
	public static void main(String[] args) {
		int anInteger = 2;
		double decimalNumber = 2.0;
		String textInformation = "Some text";
		boolean truthyInformation = false;
		// And sometimes they can work together or produce one another
		String combinedString = "The number two: " + anInteger; // The number two: 2
		boolean isTwoTwo = anInteger == decimalNumber; // true
		int zero = anInteger - decimalNumber // 0
	}
}

Data types exist in Python, but we are under no obligation to be specific about which data type a certain variable might hold. Variables can hold any type of data at any time. This has its pros and cons, but generally it means our code is less cluttered.

anInteger = 2
decimalNumber = 2.0
textInformation = "Some text"
truthyInformation = False
# And as in Java, we can have them interact
combinedString = f"The number two: {anInteger}" # The number two: 2
isTwoTwo = anInteger == decimalNumber
zero = anInteger - decimalNumber

Decision Making

The classical construct for decision making in computer programs is the if statement.

class Main {
	public static void main(String[] args) {
		int age = 18;
		 
		if (age < 21) {
			System.out.println("Still not legal.");
		} else if (age == 21) {
			System.out.println("Congratulations on becoming legal!");
		} else {
			System.out.println("You're legal!");
		}
	}
}

A similar program in Python is just as simple:

age = 18

if age < 21:
    print("Still not legal.")
elif age == 21:
    print("Congratulations on becoming legal!")
else:
    print("You're legal!")

Programs with pre-determined input aren’t very engaging, though. Let’s try getting some user input from the console. In Java this is a little complicated:

import java.util.Scanner;

class Main {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		System.out.println("How old are you?");
		int age = scan.nextInt();
		
		scan.close();
		
		if (age < 21) {
			System.out.println("Still not legal.");
		} else if (age == 21) {
			System.out.println("Congratulations on becoming legal!");
		} else {
			System.out.println("You're legal!");
		}
	}
}

By comparison, this is a lot simpler in Python:

age = int(input("How old are you?")) # Prompt the user to enter their age, then convert the resulting string into an integer

if age < 21:
    print("Still not legal.")
elif age == 21:
    print("Congratulations on becoming legal!")
else:
    print("You're legal!")

Python is designed with simplicity for convenient little command-line programs in mind, and yet it still sees heavy use in fields like data science, web development and cyber security.

More Complex Data and Iteration

Built-In Data Structures

Java offered us more than primitive data types for holding single values. It gave us access to more complex types of data, like arrays, ArrayLists and HashMaps. Data types that hold other data types in a specific form or shape are called data structures. Let’s look at how some of the native data structures in Java are used and compare that code to a Python equivalent.

class Main {
	public static void main(String[] args) {
		int[] ages = {14, 18, 22, 25};
		// Now let's iterate over the array and print out how many people in this list are legal
		int amountLegal = 0;
		for (int i = 0; i < ages.length; i++) {
			if (ages[i] >= 21) {
				amountLegal++;
			}
		}
		
		System.out.println(amountLegal + " of " + ages.length + " people legal");
	}
}

In the example above, we do the following

  1. Create an integer array of ages that we can use a for loop to “iterate” over
  2. Create an integer variable to store the amount of people in the list who are legal
  3. Iterate over the array with a for loop by creating an index i and incrementing it on every step
  4. Check if the age of each person stored in the array is greater than or equal to 21
  5. Increment the amountLegal variable if it is, don’t do anything if it’s not

But the truth is that this is a lot more complex than it has to be. A Python example will demonstrate why:

ages = [14, 18, 22, 25]

amountLegal = 0

for age in ages:
    if age >= 21:
        amountLegal += 1 # Set amountLegal to itself + 1

print(f"{amountLegal} of {ages.length} people legal")

The code is a lot shorter, and a lot more self explanatory in Python. If you haven’t noticed yet, combining variable values with string literals is a lot cleaner in Python than in Java. Simply include an f before the string literal, and include any variables or expressions in braces to have them evaluated before the string is used anywhere.

Java arrays have some limitations on them. In order to grow and shrink them whenever we want, we need to use an ArrayList. In Python, native arrays (called lists) already implement these functionalities, so we don’t need to worry about differentiating between two different data structures that serve, essentially, the same purpose.

Let’s look at a HashMap example. If you didn’t learn about HashMaps in school, they are a simple data structure for storing “key-value pairs”. All this means is that instead of “looking up” or accessing data in a HashMap using a numerical index as we do with arrays, we access data using a “key” which can be of any given type, and is specified when we create an entry in the HashMap. This is easier to understand through an example:

import java.util.HashMap;

class Main {
	public static void main(String[] args) {
		HashMap<String, String> phoneBook = new HashMap<String, String>();
		phoneBook.put("Jess", "6091234567");
		phoneBook.put("Ambika", "6090987654");
		
		// and when we want to access a value from the HashMap
		
		System.out.println("Ambika's phone number: " + phoneBook.get("Ambika"));
	}
}

HashMaps are a convenient way to store data that you might want to look up later by name, ID, etc.

Python calls HashMaps “dictionaries” and makes them easy to work with:

phoneBook = {
    "Jess" : "6091234567",
    "Ambika" : "6090987654"
}

print(f"Ambika's phone number: {phoneBook['ambika']}")

Note on Functions and Methods

In Java, your classes can have self-contained snippets of functionality in them called “methods”. Methods exist in Python and other languages too. However, “method” is a term that pertains specifically to classes. The more general term for a self-contained snippet of functionality is simply “function”.

Since in Python not everything needs to be in a class, you might find that you write more functions than methods. Meanwhile, in Java you only ever have the option to write methods.

In Java our methods sometimes looked like this

class Main {
	private void greet(String name) {
		System.out.println("Hello " + name);
	}
	
	public static void main(String[] args) {
		greet("Ambika");
	}
}

A Python equivalent, using a function instead, looks like this:

def greet(name):
    print(f"Hello {name}")

def is short for “define” as we’re defining a function. As previously explained, we’re not obligated to specify the type of anything here.

Custom Data Types: Classes

Built-in data structures are fun enough to mess around with, but we also make heavy use of data types of our own creation in Java, that is to say, classes.

class Person {
	private String name;
	private int age;
	private ArrayList<Person> friends;
	
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public String getName() {
		return this.name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public int getAge() {
		return this.age;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	public ArrayList<Person> getFriends() {
		return this.friends;
	}
	
	public void setFriends(ArrayList<Person> friends) {
		this.friends = friends;
	}
	
	public void displayFriends() {
		// using a foreach loop
		for (Person friend : this.friends) {
			System.out.println(friend.getName());
		}
	}
	
	public void addFriend(Person friend) {
		this.friends.add(friend);
	}
}

class Main {
	public static void main(String[] args) {
		Person ambika = new Person("Ambika", 18);
		Person jess = new Person("Jess", 18);
		Person shakib = new Person("Shakib", 18);
		ambika.addFriend(jess);
		ambika.addFriend(shakib);
		
		ambika.displayFriends();
	}
}

A popular and age-old complaint about Java is the nonsensical length that custom classes reach due to the tedious nature of getters and setters, which most popular object oriented languages today have at least abstracted away if they’re still being used in the background.

Let’s look at the above example in Python:

class Person:
    def __init__(self, name, age): # This is the constructor
        self.name = name
	self.age = age
	self.friends = []
    
    def addFriend(self, friend): # def is short for define
        self.friends.append(friend)
    
    def displayFriends(self): # All methods accessing the properties must have self as a parameter
        for friend in self.friends:
            print(friend.name)

ambika = Person("Ambika", 18)
jess = Person("Jess", 18)
shakib = Person("Shakib", 18)

ambika.addFriend(jess)
ambika.addFriend(shakib)
ambika.displayFriends()

I won’t go deeper into the specifics of more object oriented features such as inheritance, but the syntax is simple enough that once you have a grasp on the content of this brief tutorial, you should have no problem learning it yourself.

File IO

It’s easier to write a useful program if the program doesn’t lose all memory of previous user interactions every time you shut it down. Reading information from a file (Input) and being able to store data in a file (Output) helps us circumvent that problem.

Let’s look at a Java program that creates a file and stores some information in it if the file doesn’t already exist, and reads from the file if it does exist.

import java.io.*;
import java.util.Scanner;

class Main {
	public static void main(String[] args) {
		File nameFile = new File("./nameFile");
		
		try {
			if (nameFile.createNewFile()) {
				Scanner scan = new Scanner(System.in);
				System.out.println("What's your name?");
				String name = scan.nextLine();
				scan.close();
				
				FileWriter writer = new FileWriter("./nameFile");
				writer.write(name);
			} else {
				Scanner fileReader = new Scanner(nameFile);
				System.out.println("Your name is " + fileReader.nextLine());
				fileReader.close();
			}
		} catch (IOException e) {
			System.out.println("An error occurred");
			e.printStackTrace();
		}
	}
}

The program is simple enough. If a name file doesn’t exist, it creates one, asks you for your name and then writes your name to the file. If the file does exist, it simply reads out your name from the file. This is a lot easier in Python:

from os import path

if path.exists("./nameFile"):
    with open("./nameFile", "r") as nameFile:
        print(f"Your name is {nameFile.read()}")
else:
    with open("./nameFile", "w+") as nameFile:
        name = input("What's your name? ")
        nameFile.write(name)

with is a Python construct for operating on files in a way that automatically closes them once you’re done with them. "r" and "w+" are “modes” for accessing files. "r" is read-only mode, and "w+" is write and create-if-not-exists mode. You can learn more about working with files in python here.

Synthesis

If you were able to wrap your head around the examples so far, you now know enough Python syntax to do some relatively useful things. To prove it to you, I’m going to walk you through creating a short program that will allow you to store your friends' birthdays in a file and retrieve them later if you ever wish to do so.

The program should work like this:

  1. You, the user, should be asked whether you’re storing a birthday or trying to look one up
  2. If you’re storing a birthday, you should be asked whose birthday it is and when it is
  3. If you’re looking one up, you should be asked whose birthday you’re looking for. Additionally, you should have the option to list all the birthdays you have saved

We’re going to use a specific type of file to store birthdays called a JSON file. JSON files essentially store HashMaps in files. This saves us the trouble of having to figure out how exactly we want to format the file we store birthdays in. We can simply create a dictionary in Python and write it directly to a JSON file. When we read the JSON file, it will come back to us as a Python dictionary.

Let’s get started.

First we’re going to want to load up the birthdays file if it exists already, and create it if it doesn’t.

from os import path
import json

if path.exists("./birthdays.json"):
    with open("./birthdays.json", "r") as birthday_file:
        # Load the birthday_file into a variable called
        # birthdays as a dictionary
        birthdays = json.load(birthday_file)
else:
    with open("./birthdays.json", "w+") as birthday_file:
        birthdays = {} # Empty dictionary for now

As explained by the included comment, json.load is a function that takes a JSON file as input, reads it, and returns a dictionary based on the contents of the JSON file.

Now we should create the interactive part of the program. We can create a menu system by providing numbers alongside options and having the user enter a number to express which option they’d like to select:

menu_1 = int(input("Are you ...\n1. Storing/Updating a birthday\n2. Looking up a birthday\n\nYour choice: "))

if menu_1 == 1:
    ...

If the user wants to store or update a birthday, all we have to do is

  1. Ask whose birthday it is
  2. Ask when the birthday is
  3. Store those two things as an entry in the birthdays dictionary like so

birthdays[birthday_person] = birthday

birthday_person is a string and will be used as the key, and birthday, also a string, will be used as the value.

if menu_1 == 1:
    birthday_person = input("Whose birthday is it? ")
    birthday = input("When is their birthday? (MM/DD/YYYY) ")
    # Creating a dictionary entry where the key is their name
    # and the value is their birthday
    birthdays[birthday_person] = birthday

We can deal with writing that information to the file later on.

If the user wants to look up a birthday, we should ask if they have a specific person in mind or if they’d like to view all the stored birthdays.

There’s something to beware of here: if the user wants to look up a specific person’s birthday and that person isn’t in the dictionary, we need to figure that out and let them know. There are two ways we could do this:

  1. Check if birthday_person is in birthdays.keys(). Every dictionary in Python has a method called keys() that returns a list of all the keys in the dictionary, so if the person’s name isn’t in that list, we don’t have their birthday stored
  2. Wait for a KeyError to be thrown and catch the exception it throws. If you try to look up a key in a dictionary when there’s no entry with that key, Python will throw an exception called KeyError. You could always catch the exception and respond accordingly, but we’ll be going with the first method.
elif menu_1 == 2:
    menu_2 = int(input("Would you like to ...\n1. Look up someone's birthday\n2. View all stored birthdays\n\nYour choice: "))
    if menu_2 == 1:
        birthday_person = input("Whose birthday are you looking up? ")
        # Check to make sure the entered name is in the dictionary of
        # birthdays. The keys() method on a dictionary returns a list of
        # keys for that dictionary
        if birthday_person in birthdays.keys(): 
            print(f"{birthday_person}'s birthday is on {birthdays[birthday_person]}")
        else:
            print(f"{birthday_person}'s birthday is not stored.")

If we want to print out all the birthdays that are currently stored, all we need to do is for loop over birthdays.keys() like so:

    elif menu_2 == 2:
        print("All stored birthdays are listed here:")
        for birthday_person in birthdays.keys():
            print(f"{birthday_person}'s birthday is on {birthdays[birthday_person]}")

Now all we need to do is handle invalid number entries and make sure we write any changes we’ve made to the birthdays dictionary to the JSON file:

    else:
        print("Invalid entry")
else:
    print("Invalid entry")

# Update the birthdays file
with open("./birthdays.json", "w") as birthday_file:
    # Dump the contents of the birthdays dictionary into the birthday_file
    json.dump(birthdays, birthday_file)

The json.dump function takes a dictionary as well as a JSON file as input, and writes the contents of the dictionary to the file.

Let’s put it all together:

from os import path
import json

if path.exists("./birthdays.json"):
    with open("./birthdays.json", "r") as birthday_file:
        # Load the birthday_file into a variable called
        # birthdays as a dictionary
        birthdays = json.load(birthday_file)
else:
    with open("./birthdays.json", "w+") as birthday_file:
        birthdays = {} # Empty dictionary for now

menu_1 = int(input("Are you ...\n1. Storing/Updating a birthday\n2. Looking up a birthday\n\nYour choice: "))

if menu_1 == 1:
    birthday_person = input("Whose birthday is it? ")
    birthday = input("When is their birthday? (MM/DD/YYYY) ")
    # Creating a dictionary entry where the key is their name
    # and the value is their birthday
    birthdays[birthday_person] = birthday
elif menu_1 == 2:
    menu_2 = int(input("Would you like to ...\n1. Look up someone's birthday\n2. View all stored birthdays\n\nYour choice: "))
    if menu_2 == 1:
        birthday_person = input("Whose birthday are you looking up? ")
        # Check to make sure the entered name is in the dictionary of
        # birthdays. The keys() method on a dictionary returns a list of
        # keys for that dictionary
        if birthday_person in birthdays.keys(): 
            print(f"{birthday_person}'s birthday is on {birthdays[birthday_person]}")
        else:
            print(f"{birthday_person}'s birthday is not stored.")
    elif menu_2 == 2:
        print("All stored birthdays are listed here:")
        for birthday_person in birthdays.keys():
            print(f"{birthday_person}'s birthday is on {birthdays[birthday_person]}")
    else:
        print("Invalid entry")
else:
    print("Invalid entry")

# Update the birthdays file
with open("./birthdays.json", "w") as birthday_file:
    # Dump the contents of the birthdays dictionary into the birthday_file
    json.dump(birthdays, birthday_file)

If you peek into the birthdays.json file, you’ll find that everything is stored almost exactly as they would be if we were creating a dictionary in Python.

Closure

My hope for this article is that you, the reader, will walk away from it with a drive to learn a programming language that is easy, and yet remains fun and powerful. Being able to work in Python will help you achieve more as a programmer without the headaches that come pre-packaged with Java.

If you are excited to get started writing Python for real, consider checking out this post of mine, where I explain how to install Python locally, set up a development environment for it, and start writing Discord bots.