Welcome to Python 101

Welcome! This notebook is appropriate for people who have never programmed before. A few tips:

  • To execute a cell, click in it and then type [shift] + [enter]
  • This notebook's kernel will restart if the page becomes idle for 10 minutes, meaning you'll have to rerun steps again
  • Try.jupyter.org is awesome, and Rackspace is awesome for hosting this, but you will want your own Python on your computer too. Hopefully you are in a class and someone helped you install. If not:
    • Anaconda is great if you use Windows or will only use Python for data analysis.
    • If you want to contribute to open source code, you want the standard Python release. (Follow the Hitchhiker's Guide to Python.)

Outline

  • Operators and functions
  • Data and container types
  • Control structures
  • I/O, including basic web APIs
  • How to write and run a Python script

First, try Python as a calculator.

Python can be used as a shell interpreter. After you install Python, you can open a command line terminal (e.g. powershell or bash), type python3 or python, and a Python shell will open.

For now, we are using the notebook.

Here is simple math. Go to town!


In [126]:
1 + 1


Out[126]:
2

In [127]:
3 / 4  # caution: in Python 2 the result will be an integer


Out[127]:
0.75

In [128]:
7 ** 3


Out[128]:
343

Challenge for you

The arithmetic operators in Python are:

+   -   *   /   **   %   //

Use the Python interpreter to calculate:

  • 16 times 26515
  • 1835 modulo 163

(psst...) If you're stuck, try

help()

and then in the interactive box, type symbols

More math requires the math module


In [129]:
import math

print("The square root of 3 is:", math.sqrt(3))
print("pi is:", math.pi)
print("The sin of  90 degrees is:", math.sin(math.radians(90)))


The square root of 3 is: 1.7320508075688772
pi is: 3.141592653589793
The sin of  90 degrees is: 1.0
  • The import statement imports the module into the namespace
  • Then access functions (or constants) by using:
    <module>.<function>
    
  • And get help on what is in the module by using:
    help(<module>)
    

Challenge for you

Hint: help(math) will show all the functions...

  • What is the arc cosine of 0.743144 in degrees?

In [130]:
from math import acos, degrees  # use 'from' sparingly

int(degrees(acos(0.743144)))  # 'int' to make an integer


Out[130]:
42

Math takeaways

  • Operators are what you think
  • Be careful of unintended integer math
  • the math module has the remaining functions

Strings

(Easier in Python than in any other language ever. Even Perl.)

Strings

Use help(str) to see available functions for string objects. For help on a particular function from the class, type the class name and the function name: help(str.join)

String operations are easy:

s = "foobar"

"bar" in s
s.find("bar")
index = s.find("bar")
s[:index]
s[index:] + "  this is intuitive! Hooray!"
s[-1]  # The last element in the list or string

Strings are immutable, meaning they cannot be modified, only copied or replaced. (This is related to memory use, and interesting for experienced programmers ... don't worry if you don't get what this means.)


In [131]:
# Here's to start.
s = "foobar"

"bar" in s


Out[131]:
True

In [132]:
# You try out the other ones!
s.find("bar")


Out[132]:
3

Challenge for you

Using only string addition (concatenation) and the function str.join, combine declaration and sayings :

declaration = "We are the knights who say:\n"
sayings = ['"icky"'] * 3 + ['"p\'tang"']
# the (\') escapes the quote

to a variable, sentence, that when printed does this:

>>> print(sentence)
We are the knights who say:
"icky", "icky", "icky", "p'tang"!

In [133]:
help(str.join)


Help on method_descriptor:

join(...)
    S.join(iterable) -> str
    
    Return a string which is the concatenation of the strings in the
    iterable.  The separator between elements is S.


In [134]:
declaration = "We are now the knights who say:\n"
sayings = ['"icky"'] * 3 + ['"p\'tang"']

# You do the rest -- fix the below  :-)
print(sayings)


['"icky"', '"icky"', '"icky"', '"p\'tang"']

Don't peek until you're done with your own code!


In [135]:
sentence = declaration + ", ".join(sayings) + "!"
print(sentence)
print()    # empty 'print' makes a newline


We are now the knights who say:
"icky", "icky", "icky", "p'tang"!


In [136]:
# By the way, you use 'split' to split a string...
#  (note what happens to the commas):
print(" - ".join(['ni'] * 12))
print("\n".join("icky, icky, icky, p'tang!".split(", ")))


ni - ni - ni - ni - ni - ni - ni - ni - ni - ni - ni - ni
icky
icky
icky
p'tang!

String formatting

There are a bunch of ways to do string formatting:

  • C-style:
    "%s is: %.3f (or %d in Indiana)" % \
          ("Pi", math.pi, math.pi)
    # %s = string
    # %0.3f = floating point number, 3 places to the left of the decimal
    # %d = decimal number
    #
    # Style notes:
    #     Line continuation with '\' works but
    #     is frowned upon. Indent twice
    #     (8 spaces) so it doesn't look
    #     like a control statement
    

In [137]:
print("%s is: %.3f (well, %d in Indiana)" % ("Pi", math.pi, math.pi))


Pi is: 3.142 (well, 3 in Indiana)
  • New in Python 2.6, str.format doesn't require types:
    "{0} is: {1} ({1:3.2} truncated)".format(
          "Pi", math.pi)
    # More style notes:
    #    Line continuation in square or curly
    #    braces or parenthesis is better.
    

In [138]:
# Use a colon and then decimals to control the
# number of decimals that print out.
#
# Also note the number {1} appears twice, so that
# the argument `math.pi` is reused.
print("{0} is: {1} ({1:.3} truncated)".format("Pi", math.pi))


Pi is: 3.141592653589793 (3.14 truncated)
  • And Python 2.7+ allows named specifications:
    "{pi} is {pie:05.3}".format(
          pi="Pi", pie=math.pi)
    # 05.3 = zero-padded number, with
    #        5 total characters, and
    #        3 significant digits.
    

In [139]:
# Go to town -- change the decimal places!
print("{pi} is: {pie:05.2}".format(pi="Pi", pie=math.pi))


Pi is: 003.1

String takeaways

  • str.split and str.join, plus the regex module (pattern matching tools for strings), make Python my language of choice for data manipulation
  • There are many ways to format a string
  • help(str) for more

Quick look at other types


In [140]:
# Boolean
x = True
type(x)


Out[140]:
bool

Python has containers built in...

Lists, dictionaries, sets. We will talk about them later. There is also a library collections with additional specialized container types.


In [141]:
# Lists can contain multiple types
x = [True, 1, 1.2, 'hi', [1], (1,2,3), {}, None]
type(x)
# (the underscores are for special internal variables)


Out[141]:
list

In [142]:
# List access. Try other numbers!
x[1]


Out[142]:
1

In [143]:
print("x[0] is:", x[0], "... and x[1] is:", x[1])  # Python is zero-indexed


x[0] is: True ... and x[1] is: 1

In [144]:
x.append(set(["a", "b", "c"]))

for item in x:
    print(item, "... type =", type(item))


True ... type = <class 'bool'>
1 ... type = <class 'int'>
1.2 ... type = <class 'float'>
hi ... type = <class 'str'>
[1] ... type = <class 'list'>
(1, 2, 3) ... type = <class 'tuple'>
{} ... type = <class 'dict'>
None ... type = <class 'NoneType'>
{'a', 'c', 'b'} ... type = <class 'set'>

If you need to check an object's type, do this:

isinstance(x, list)
isinstance(x[1], bool)

In [145]:
# You do it!
isinstance(x, tuple)


Out[145]:
False

Caveat

Lists, when copied, are copied by pointer. What that means is every symbol that points to a list, points to that same list.

Same with dictionaries and sets.

Example:

fifth_element = x[4]
fifth_element.append("Both!")
print(fifth_element)
print(x)

Why? The assignment (=) operator copies the pointer to the place on the computer where the list (or dictionary or set) is: it does not copy the actual contents of the whole object, just the address where the data is in the computer. This is efficent because the object could be megabytes big.


In [146]:
# You do it!
fifth_element = x[4]
print(fifth_element)

fifth_element.append("Both!")
print(fifth_element)

# and see, the original list is changed too!
print(x)


[1]
[1, 'Both!']
[True, 1, 1.2, 'hi', [1, 'Both!'], (1, 2, 3), {}, None, {'a', 'c', 'b'}]

To make a duplicate copy you must do it explicitly

The copy module

Example:

import copy

# -------------------- A shallow copy
x[4] = ["list"]
shallow_copy_of_x = copy.copy(x)
shallow_copy_of_x[0] = "Shallow copy"
fifth_element = x[4]
fifth_element.append("Both?")

def print_list(l):
   print("-" * 10)
   for elem in l:
       print(elem)
   print()


# look at them
print_list(shallow_copy_of_x)
print_list(x)
fifth_element

In [147]:
import copy

# -------------------- A shallow copy
x[4] = ["list"]
shallow_copy_of_x = copy.copy(x)
shallow_copy_of_x[0] = "Shallow copy"
fifth_element = x[4]
fifth_element.append("Both?")

In [148]:
# look at them
def print_list(l):
   print("-" * 8, "the list, element-by-element", "-" * 8)
   for elem in l:
       print(elem)
   print()

print_list(shallow_copy_of_x)
print_list(x)


-------- the list, element-by-element --------
Shallow copy
1
1.2
hi
['list', 'Both?']
(1, 2, 3)
{}
None
{'a', 'c', 'b'}

-------- the list, element-by-element --------
True
1
1.2
hi
['list', 'Both?']
(1, 2, 3)
{}
None
{'a', 'c', 'b'}

And here is a deep copy

# -------------------- A deep copy

x[4] = ["list"]
deep_copy_of_x = copy.deepcopy(x)
deep_copy_of_x[0] = "Deep copy"
fifth_element = deep_copy_of_x[4]
fifth_element.append("Both?")

# look at them
print_list(deep_copy_of_x)
print_list(x)
fifth_element

In [149]:
# -------------------- A deep copy

x[4] = ["list"]
deep_copy_of_x = copy.deepcopy(x)
deep_copy_of_x[0] = "Deep copy"
fifth_element = deep_copy_of_x[4]
fifth_element.append("Both? -- no, just this one got it!")

# look at them
print(fifth_element)
print("\nand...the fifth element in the original list:")
print(x[4])


['list', 'Both? -- no, just this one got it!']

and...the fifth element in the original list:
['list']

Common atomic types

boolean integer float string None
True 42 42.0 "hello" None

Common container types

list tuple set dictionary
  • Iterable
  • Mutable
  • No restriction on elements
  • Elements are ordered
  • Iterable
  • Immutable
  • Elements must be hashable
  • Elements are ordered
  • Iterable
  • Mutable
  • Elements are
    unique and must
    be hashable
  • Elements are not ordered
  • Iterable
  • Mutable
  • Key, value pairs.
    Keys are unique and
    must be hashable
  • Keys are not ordered

Iterable

You can loop over it

Mutable

You can change it

Hashable

A hash function converts an object to a number that will always be the same for the object. They help with identifying the object. A better explanation kind of has to go into the guts of the code...

Container examples

List

  • To make a list, use square braces.

In [150]:
l = ["a", 0, [1, 2] ]
l[1] = "second element"

type(l)


Out[150]:
list

In [151]:
print(l)


['a', 'second element', [1, 2]]
  • Items in a list can be anything:
    sets, other lists, dictionaries, atoms

In [152]:
indices = range(len(l))
print(indices)


range(0, 3)

In [153]:
# Iterate over the indices using i=0, i=1, i=2
for i in indices:
    print(l[i])


a
second element
[1, 2]

In [154]:
# Or iterate over the items in `x` directly
for x in l:
    print(x)


a
second element
[1, 2]

Tuple

To make a tuple, use parenthesis.


In [155]:
t = ("a", 0, "tuple")
type(t)


Out[155]:
tuple

In [156]:
for x in t:
    print x


  File "<ipython-input-156-d7e81b4073bb>", line 2
    print x
          ^
SyntaxError: Missing parentheses in call to 'print'

Set

To make a set, wrap a list with the function set().

  • Items in a set are unique
  • Lists, dictionaries, and sets cannot be in a set

In [157]:
s = set(['a', 0])
if 'b' in s:
    print("has b")

In [158]:
s.add("b")
s.remove("a")

if 'b' in s:
    print("has b")


has b

In [159]:
l = [1,2,3]
try:
    s.add(l)
except TypeError:
    print("Could not add the list")
    #raise  # uncomment this to raise an error


Could not add the list

Dictionary

To make a dictionary, use curly braces.

  • A dictionary is a set of key,value pairs where the keys are unique.
  • Lists, dictionaries, and sets cannot be dictionary keys
  • To iterate over a dictionary use items

In [160]:
#   two ways to do the same thing
d = {"mother":"hamster",
     "father":"elderberries"}
d = dict(mother="hamster",
         father="elderberries")

In [161]:
d['mother']


Out[161]:
'hamster'

In [162]:
print("the dictionary keys:", d.keys())
print()
print("the dictionary values:", d.values())


the dictionary keys: dict_keys(['father', 'mother'])

the dictionary values: dict_values(['elderberries', 'hamster'])

In [163]:
# When iterating over a dictionary, use items() and two variables:
for k, v in d.items():
    print("key: ", k, end="  ... ")
    print("val: ", v)


key:  father  ... val:  elderberries
key:  mother  ... val:  hamster

In [164]:
# If you don't you will just get the keys:
for k in d:
    print(k)


father
mother

Type takeaways

  • Lists, tuples, dictionaries, sets all are base Python objects
  • Be careful of duck typing
  • Remember about copy / deepcopy
# For more information, use help(object)
help(tuple)
help(set)
help()

Function definition and punctuation

The syntax for creating a function is:

def function_name(arg1, arg2, kwarg1=default1):
    """Docstring goes here -- triple quoted."""
    pass  # the 'pass' keyword means 'do nothing'


# The next thing unindented statement is outside
# of the function. Leave a blank line between the
# end of the function and the next statement.
  • The def keyword begins a function declaration.
  • The colon (:) finishes the signature.
  • The body must be indented. The indentation must be exactly the same.
  • There are no curly braces for function bodies in Python — white space at the beginning of a line tells Python that this line is "inside" the body of whatever came before it.

Also, at the end of a function, leave at least one blank line to separate the thought from the next thing in the script.


In [165]:
def function_name(arg1, arg2, kwarg1="my_default_value"):
    """Docstring goes here -- triple quoted."""
    pass  # the 'pass' keyword means 'do nothing'

In [166]:
# See the docstring appear when using `help`
help(function_name)


Help on function function_name in module __main__:

function_name(arg1, arg2, kwarg1='my_default_value')
    Docstring goes here -- triple quoted.

Whitespace matters

The 'tab' character '\t' counts as one single character even if it looks like multiple characters in your editor.

But indentation is how you denote nesting!

So, this can seriously mess up your coding. The Python style guide recommends configuring your editor to make the tab keypress type four spaces automatically.

To set the spacing for Python code in Sublime, go to Sublime TextPreferencesSettings - MoreSyntax Specific - User

It will open up the file Python.sublime-settings. Please put this inside, then save and close.

{
    "tab_size": 4,
    "translate_tabs_to_spaces": true
}

Your first function

Copy this and paste it in the cell below

def greet_person(person):
    """Greet the named person.

    usage:
        >>> greet_person("world")
        hello world
    """
    print('hello', person)

In [167]:
# Paste the function definition below:

In [168]:
# Here's the help statement
help(greet_person)


Help on function greet_person in module __main__:

greet_person(person)
    Greet the named person.
    
    usage:
        >>> greet_person("world")


In [169]:
# And here's the function in action!
greet_person("world")


hello world

Duck typing

Python's philosophy for handling data types is called duck typing (If it walks like a duck, and quacks like a duck, it's a duck). Functions do no type checking — they happily process an argument until something breaks. This is great for fast coding but can sometimes make for odd errors. (If you care to specify types, there is a standard way to do it, but don't worry about this if you're a beginner.)

Challenge for you

Create another function named greet_people that takes a list of people and greets them all one by one. Hint: you can call the function greet_person.


In [170]:
# your function
def greet_people(list_of_people)
    """Documentation string goes here."""
    # You do it here!
    pass


  File "<ipython-input-170-01f6ec0f31e4>", line 2
    def greet_people(list_of_people)
                                    ^
SyntaxError: invalid syntax

don't peek...


In [171]:
def greet_people(list_of_people):
    for person in list_of_people:
        greet_person(person)

In [172]:
greet_people(["world", "awesome python user!", "rockstar!!!"])


hello world
hello awesome python user!
hello rockstar!!!

Quack quack

Make a list of all of the people in your group and use your function to greet them:

people = ["King Arthur",
          "Sir Galahad",
          "Sir Robin"]
greet_people(people)

# What do you think will happen if I do:
greet_people("pyladies")

In [173]:
# Try it!

WTW?

Remember strings are iterable...

quack!
quack!

Whitespace / duck typing takeways

  • Indentation is how to denote nesting in Python
  • Do not use tabs; expand them to spaces
  • If it walks like a duck and quacks like a duck, it's a duck

Control structures

Common comparison operators

== != <= or <
>= or >
x in (1, 2) x is None
x is not None
equals not equals less or
equal, etc.
works for sets,
lists, tuples,
dictionary keys,
strings
just for None

If statement

The if statement checks whether the condition after if is true. Note the placement of colons (:) and the indentation. These are not optional.

  • If it is, it does the thing below it.
  • Otherwise it goes to the next comparison.
  • You do not need any elif or else statements if you only want to do something if your test condition is true.

Advanced users, there is no switch statement in Python.


In [174]:
# Standard if / then / else statement.
#
# Go ahead and change `i`
i = 1

if i is None:
    print("None!")
elif i % 2 == 0:
    print("`i` is an even number!")
else:
    print("`i` is neither None nor even")


`i` is neither None nor even

In [175]:
# This format is for very short one-line if / then / else.
# It is called a `ternary` statement.
#
"Y" if i==1 else "N"


Out[175]:
'Y'

While loop

The while loop requires you to set up something first. Then it tests whether the statement after the while is true. Again note the colon (:) and the indentation.

  • If the condition is true, then the body of the while loop will execute
  • Otherwise it will break out of the loop and go on to the next code underneath the while block

In [176]:
i = 0
while i < 3:
    print("i is:", i)
    i += 1

print("We exited the loop, and now i is:", i)


i is: 0
i is: 1
i is: 2
We exited the loop, and now i is: 3

For loop

The for loop iterates over the items after the for, executing the body of the loop once per item.


In [177]:
for i in range(3):
    print("in the for loop. `i` is:", i)

print()
print("outside the for loop. `i` is:", i)


in the for loop. `i` is: 0
in the for loop. `i` is: 1
in the for loop. `i` is: 2

outside the for loop. `i` is: 2

In [178]:
# or loop directly over a list or tuple
for element in ("one", 2, "three"):
    print("in the for loop. `element` is:", element)

print()
print("outside the for loop. `element` is:", element)


in the for loop. `element` is: one
in the for loop. `element` is: 2
in the for loop. `element` is: three

outside the for loop. `element` is: three

Challenge for you

Please look at this code and think of what will happen, then copy it and run it. We introduce break and continue...can you tell what they do?

  • When will it stop?
  • What will it print out?
  • What will i be at the end?
for i in range(20):
    if i == 15:
        break
    elif i % 2 == 0:
        continue
    for j in range(5):
        print(i + j, end="...")
    print()  # newline

In [179]:
# Paste it here, and run!

You are done, welcome to Python!

... and you rock!

Now join (or start!) a friendly PyLadies group near you ...

PyLadies locations

Psst...contribute to this repo!

Here is the link to the github repo that hosts these . Make them better!