An Introduction to Python for new Programmers

Welcome to An Introduction to Python for new Programmers! This iPython notebook serves as an instructor-led guide to the Python programming language, particularly for those who are new to programming or have very limited programming experience. iPython notebooks are a novel form of communicating about programming; creating an environment where both text and live code can be executed in an explanatory fashion. Parts of this document will contain live Python code that is interpreted by the notebook and whose output will be rendered directly to the screen. If you would like to follow along on your laptop, you can install iPython and download this workbook from github/intro-to-python.

Before we get Started

Although this is an introductory course, some prerequisites are required. In particular, the student must have Python installed and be familiar with using Python on his or her operating system. They must also have familiarity with the command line. The following are suggested tasks to perform before this course:

If you can open up an interpreter and have the words "Hello World" print to the screen, then we're ready to go!

Learning how to Learn how to Code

So, let's be clear- what can we accomplish in a two to three hour session? Obviously we're not going to make you an expert programmer in this time, nor are we going to impart a comprehensive theory of programming. However, there is one fundamental concept about programming that I would like ensure you all take away: programming isn't about knowing syntax it's about learning. Therefore, what were going to try to enable you to do today is help you learn how to learn how to code.

Programming is a creative discipline, and thanks to the wide applicability of programming to a variety of domains, true innovation happens often. Programmers stand on the shoulders of giants, and in order to continually improve his or her craft, a programmer must constantly be in a state of education. From reading about new programming paradigms, languages, or frameworks to experimental approaches to reading other' code- programming is is a community activity that encourages the sharing of ideas.

In particular we'll focus on clear expression of code and readability. By ensuring you can write code in a readable form, it will help you to read other's code as well!

What is Programming?

Programming is the act of creating a set of instructions to transform input data to some kind of output.

Yeh- it's that simple. We're making recipes of ingredients and instructions.

However, instead of food, we cook with numbers and strings. The instructions are defined as a formal language.

The instructions are interpreted and executed from top to bottom, and when the interpreter runs out of instructions, the program is done!

Consider the following simple program:


In [ ]:
# Compute the area of a triangle

# Ingredients
base   = 4
height = 7

# Instructions
area = 0.5 * base * height
print area

This small program includes quite a few components:

  • Comments
  • Assignment
  • Variables
  • Multiplication
  • Output

Interactivity

But why is this idea so powerful? It's because variables are meant to be... variable.


In [ ]:
# The area of a circle
# Must input a number or a decimal
radius = input("Enter radius: ")
area = 3.14 * radius * radius
print area

Here we create a variable called radius. Note that the name of the variable is expressive (much better than x or y). The value of variable is assigned using the = operator. In this case it is assigned the value of the return value from the input function. We can run this program over and over again and by changing the input we have changed the ouput- thus making our program dynamic. We can then use the variable throughout the program and even modify its value through code during runtime. And through this very simple concept, very complex programs from web servers to self-driving cars are built from just a few simple building blocks!

Calculation

So let's look at what computers do best- compute things!


In [ ]:
a = 2    # Integer
b = 3.4  # Float

print a + b    # Addition
print b - a    # Subtraction
print a * b    # Multiplication
print 5 % a    # Modulus

In [ ]:
a = 10
b = 3
c = 3.0

# Division?
print a / b    
print a / c

In [ ]:
a = "Hello"  # String
b = " World" # Another string

print a + b  # Concatenation

name = "Jonesey"
print "Hello, %s!" % name # String format

Comparison

True and False are booleans in Python and are used to express truth. Let's explore some comparision operators.

Note: Don't confuse assignment = with is equal to ==; this is one of the most common programmer errors.


In [ ]:
a = 10
b = 20

print a > b   # Greater than
print b >= a  # Greater than or equal to
print a == b  # is equal to
print b < a   # Less than
print a <= b   # Less than or equal to

Conditionality

Programs can make choices based on particular values of variables using conditional execution. Conditionality forks the flow of execution so that some parts of the program may be executed but others will not.

This brings up a crucial point about Python in particular- blocks of code are grouped by indentation. Every time you get to a place where you have to define a contiguous block of code (usually following a :) then everything under must be indented with the same amount of space (usually 4 space). Dedented code does not belong to the indented block.

TODO: Logic


In [ ]:
# Evaluate Temperature
temperature = input("What is today's temperature?  ")
temperature = int(temperature)

if temperature > 82:
   print "It's too hot, %i degrees will melt you." % temperature
elif temperature < 45:
   print "Are you crazy? You'll freeze at %i degrees" % temperature
else:
    print "Perfect weather! Let's go for a picnic!"

In [ ]:
a = True
b = True
c = False
d = False

if a and b:
    print "a and b == True"
    
if b or c:
    print "b and c == True"
    
if c or not d:
    print "d and c == True"

In [ ]:
if 1: 
    print "1"

if None:
    print "None"

if not None:
    print "Not None"

print None == False

a = None
b = 0

print a is None
print b is None

Repetition

The power of computers is their ability to do a repetitive task over and over again without tiring. Most programs don't just shut down on you have executing their instructions- they wait for input from the user and respond. In order to accomplish this some mechanism is required to continually execute a chunk of code.


In [ ]:
for letter in "a", "b", "c", "d", "e":
    print letter

In [ ]:
for number in range(1,10):
    if number % 2 == 0:
        print "number " + str(number) + " is even"

In [ ]:
# an import statement
from time import sleep

print "Cooking the spam."

hot_enough  = 180
temperature = 62

while temperature < hot_enough:
    print "Not hot enough..."
    sleep(1)
    temperature = temperature + 15

print "Spam is done!"

Functions

Functions allow you to define proceedures that happen over and over again in your code, almost like mini-programs that take input and return an output. Consider the following proceedural code:


In [ ]:
# Compute 8! - 4!

num     = 8
result  = 1
while num > 0:
    result = result * num
    num = num -1

num     = 4
result2 = 1
while num > 0:
    result2 = result2 + num
    num = num - 1
    
print "8! - 4! is " + str(result - result2)

Let's create a reusable chunk of code to perform the computation just once. This is far better than copy and paste; it reduces the complexity of code, makes it more readable, and makes it more maintainable.


In [ ]:
def fact(num):
    result = 1
    while num > 0:
        result = result * num
        num = num - 1
    return result

print "8! - 4! is " + str(fact(8) - fact(4))

Arguments to functions are named buckets that can have defaults associated with them. Positional arguments (arguments without a default) must be specified in the order of the arguments. Keyword arguments (those with a default) can be specified in any order, so long as they come after the positional arguments.


In [ ]:
# postional and keyword arguments
def writer(name, color="blue"):
    print name + "'s favorite color is " + color
    
writer("Samantha")
writer("Sarah", "red")
writer("Susan", color="green")

# A stub function that does nothing
def stub():
    pass

# Generic Arguments
def generic(*args, **kwargs):
    print args
    print kwargs

Data Structures

Programmers can't live on numbers and strings alone. The currency of programming is data (information), therefore we need more significant structures to represent information. The last two primitive data structures are dict and list.


In [ ]:
# A new list
 groceries = []

 # Add to list
 groceries.append("Apples")
 groceries.append("Oranges")
 print groceries.append("Cactus")

 # Access by index
 print groceries[2]

 # Find number of things in list
 print len(groceries)

 # Remove from list
 groceries.remove("Oranges")
 print groceries

In [ ]:
# A dictionary of days in months
months = {
    'January': 31,
    'February': 28,
    'March': 30,
    # ...
}

# Access by key
print months['March']

# Add new item
print 'December' in months
months['December'] = 31
print months['December']

In [ ]:
# Complex Data structures

employees = {
    "eid0001": {
        "name": "Bob Jones",
        "department": "Marketing",
        "interests": ["fishing", "deep breathing", "gatorade",]
    },
    "eid0002": {
        "name": "Sherry Lorenzo",
        "department": "Human Resources",
        "interests": ["cooking", "steganography", "cycling",],
    }
}

for employee in employees:
    print employees[employee]["name"]

Object Oriented Programming

Now that we have covered the basic building blocks of a Python program, let's discuss a programming paradigm called Object-Oriented Programming (OOP). OOP gives programmers a framework for modeling the real world by using classes - templates that describe an object's methods and attributes. Using this methodology, a programmer simply has to imagine the component interactions of the structure they're trying to model, then translate that into the executional components described above.

Some Terminology:

  • Class: A user-defined prototype for an object that defines a set of attributes that characterize any object of the class. The attributes are data members (class variables and instance variables) and methods, accessed via dot notation.
  • Class variable: A variable that is shared by all instances of a class. Class variables are defined within a class but outside any of the class's methods. Class variables aren't used as frequently as instance variables are.
  • Data member: A class variable or instance variable that holds data associated with a class and its objects.
  • Function overloading: The assignment of more than one behavior to a particular function. The operation performed varies by the types of objects (arguments) involved.
  • Instance variable: A variable that is defined inside a method and belongs only to the current instance of a class.
  • Inheritance : The transfer of the characteristics of a class to other classes that are derived from it.
  • Instance: An individual object of a certain class. An object obj that belongs to a class Circle, for example, is an instance of the class Circle.
  • Instantiation : The creation of an instance of a class.
  • Method : A special kind of function that is defined in a class definition.
  • Object : A unique instance of a data structure that's defined by its class. An object comprises both data members (class variables and instance variables) and methods.
  • Operator overloading: The assignment of more than one function to a particular operator.

In [ ]:
class Person(object):
    """
    Base class for all employees
    """
    
    population = 0
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        Person.population += 1
    
    def displayCount(self):
        print "Total people: %d" % Person.population
    
    def displayPerson(self):
        print "Name: ", self.name, ", Age: ", self.age

In [ ]:
# Creating instances
bob = Person("Bob", 35)
bob.displayCount()
bob.displayPerson()
sue = Person("Sue", 42)
bob.displayCount()

Inheritance


In [ ]:
class Employee(Person):
    
    def __init__(self, name, age, salary):
        self.salary = salary
        super(Employee, self).__init__(name, age)
    
    def displayPerson(self):
        print "Name: ", self.name, ", Salary: ", self.salary

In [ ]:
bob = Employee("Bob", 42, 768500)
bob.displayPerson()
bob.displayCount()

A Time Formatter

In order to get a feel for how simple programs can be constructed, let's take a look at simple program that I wrote and use every single day. We'll walk through each line of code together and discover how this code works. This exercise will be common as you continue to learn how to program.


In [ ]:
#!/usr/bin/env python

import sys
from datetime import datetime
from dateutil.tz import tzlocal

class Clock(object):
    
    FORMATS = {
        "code":"%a %b %d %H:%M:%S %Y %z",
        "json":"%Y-%m-%dT%H:%M:%S.%fZ",
        "cute":"%b %d, %Y", 
    }

    @classmethod
    def local_now(klass):
        return datetime.now(tzlocal())

    @classmethod
    def utc_now(klass):
        return datetime.utcnow()

    def __init__(self, formats={}):
        self.formats = self.FORMATS.copy()
        self.formats.update(formats)
     
    def _local_format(self, fmt):
        return Clock.local_now().strftime(fmt)

    def _utc_format(self, fmt):
        return Clock.utc_now().strftime(fmt)

    def get_stamp(self, name):
        name  = name.strip("-")
        mname = name + "_stamp"

        # Try to find method table first
        if hasattr(self, mname):
            method = getattr(self, mname)
            return method()

        # Try to use the format string with local timezone
        if name in self.formats:
            return self._local_format(self.formats[name])

        return None

    def print_stamp(self, name):
            stamp = self.get_stamp(name)
            if stamp:
                print stamp
            else:
                print "No stamp format for name %s" % name

    def help_stamp(self):

        output = ["Prints a timestamp represented with a format.",
                  "",
                  "The formats are stored in a lookup table with names, that",
                  "you can pass to the function. For instance, if you pass the",
                  "following arguments, you'll get the following results:",
                  ""]

        for name in ('--code', '--json'):
            output.append("\t%s: %s" % (name, self.get_stamp(name)))
    
        output.append("")
        output.append("The current formats are:")
        output.append("")

        for item in self.formats.items():
            output.append("\t%s: \"%s\"" % item)
        output.append("")

        output.append("Note that the timezone will default to the system timezone unless")
        output.append("The format requires a UTC or other timezone (like JSON)")
        output.append("")

        return "\n".join(output)

    def json_stamp(self):
        return self._utc_format(self.formats['json'])


if __name__ == "__main__":

    clock = Clock()
    clock.print_stamp("code")

In [ ]: