In [7]:
from notebook.services.config import ConfigManager
from IPython.paths import locate_profile
cm = ConfigManager(profile_dir=locate_profile(get_ipython().profile))
cm.update('livereveal', {
              'theme': 'moon',
              'transition': 'zoom',
              'start_slideshow_at': 'selected',
})


Out[7]:
{u'start_slideshow_at': 'selected', u'theme': 'moon', u'transition': 'zoom'}

Coding in Python

Dr. Chris Gwilliams

gwilliamsc@cardiff.ac.uk

Writing in Python: PEP

Python Enhancement Proposals

Unsure how your code should be written? PEP is a style guide for Python and provides details on what is expected.

  • Use 4 spaces instead of tabs
  • Lines should be 79 characters long
  • Variables should follow snake_case
    • All lower case words, separated by underscores (_)
  • Classes should be Capitalised Words (MyClassExample)

PEP

Comments

Sometimes, you need to describe your code and the logic may be a bit complicated, or it took you a while to figure it out and you want to make a note.

You can't just write some text in the file or you will get errors, this is where comments come in! Comments are descriptions that the Python interpreter ignores.

Just type a # amd what ever you want to write and voíla!

It is ALWAYS a good idea to comment your code!


In [2]:
# Does this make sense without comments?
with open('myfile.csv', 'rb') as opened_csv:
    spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
    for row in spamreader:
        print (', '.join(row))


---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-2-04109d93ef87> in <module>()
      1 # Does this make sense without comments?
----> 2 with open('myfile.csv', 'rb') as opened_csv:
      3     spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
      4     for row in spamreader:
      5         print (', '.join(row))

FileNotFoundError: [Errno 2] No such file or directory: 'myfile.csv'

In [2]:
# How about this?

#open csv file in readable format
with open('myfile.csv', 'rbU') as opened_csv:
    # read opened csv file with spaces as delimiters
    spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
    # loop through and print each line
    for row in spamreader:
        print (', '.join(row))


/usr/local/lib/python3.4/site-packages/ipykernel/__main__.py:4: DeprecationWarning: 'U' mode is deprecated
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-2-9cc1b544c150> in <module>()
      2 
      3 #open csv file in readable format
----> 4 with open('myfile.csv', 'rbU') as opened_csv:
      5     # read opened csv file with spaces as delimiters
      6     spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')

FileNotFoundError: [Errno 2] No such file or directory: 'myfile.csv'

Types

Python has a type system (variables have types), even if you do not specify it when you declare them.

  • String
  • Float
  • Boolean
  • Integer
  • None

Exercise

Give me an example of each of these types.

What is the None type?

Use the Internet to find me examples of 1 other type in Python

We will come back to type as the course progresses.

Literals

Literally a value.

All of the examples you just gave are literals.


In [2]:
"Gavin" #String Literal 
4 #Integer Literal


Out[2]:
3.14

3.14 is a float literal

Variables

Literals are all well and good for printing but what about when we need to change and store these literals?

Variables are ways of giving literal values a name in order to refer to them later.

Below, we are declaring and instantiating a variable


In [ ]:
# declared and instantiated
name = "Gavin"

# declared, but not instantiated
new_name = None

Variables in Python

Technically, Python does not have empty variables that are not instantiated. A variable exists as soon as it is assigned a value. Like this:


In [1]:
x # does not exist so cannot print it


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-401b30e3b8b5> in <module>()
----> 1 x

NameError: name 'x' is not defined

In [ ]:
x = 1
print(x)

Variables in Python

In many languages, when a variable is instantiated, it is reserved into a block of memory and the variable points to that memory address, often unique for that variable.

In Python, it is more like that memory address is tagged with the variable name. So, if we create three variables that have the same literal value, then they all point to the same memory address. Like so:


In [6]:
a = 1
b = 1
c = 1
print(id(a))
print(id(b))


4406331952
4406331952

id and Multi Variable Assignment

The id function is built into Python and returns the memory address of variables provided to it.

This is easier to see when we use multi-variable assignment in Python:


In [1]:
a,b,c = 1,1,1
name, age, yob = "chris", 26, 1989
print(name, age, yob)
print(id(name), id(age), id(yob))
a,b,c = "Name",12,"6ft"
print(a,b,c) #NOTE: always balance the left and the right. 5 variables must have 5 values!


('chris', 26, 1989)
(4357826144, 140678563648224, 140678600758184)
('Name', 12, '6ft')

Don't Call It That:

These are keywords reserved in Python, so do not name any of your variables after these! You will learn about what many of these do throughout this course.

False class finally is return
continue for lambda try True
def from nonlocal while and
del global not with as
elif if or yield assert
else import pass break except
in raise None

Types II

Python is Strongly Typed - The Python interpreter keeps track of all the variables and their associated types.

AND

Python is Dynamically Typed - Variables can be reassigned from their types. A variable is simply a value bound to a name, the variable does not hold a type, only the value does.


In [6]:
print("Hello " + "World") #ok
print("hello" + 5) #strongly typed means this cannot happen!
name = "Chris"
name = "Pi"
"pi" + 6 #Strongly typed means no adding different types together!
name = 3.14 #dynamically typed means yes to changing the type of a variable!


Hello World
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-16cc78780c92> in <module>()
      1 print("Hello " + "World") #ok
----> 2 print("hello" + 5) #strongly typed means this cannot happen!
      3 name = "Chris"
      4 name = "Pi"
      5 name + 6 #Strongly typed means no adding different types together!

TypeError: Can't convert 'int' object to str implicitly

Recap Questions

  • What is a REPL?
  • What does strongly typed mean?
  • What does dynamically typed mean?
  • What is a literal?

Variable Recap

  • Give me 3 types in Python
    • What would you use each type for?
  • How do you declare multiple variables at the same time?
  • What is wrong with the code below?

    name, age, height = 12, 'Terry'

  • Read, Eval, Print, Loop
  • Strongly typed is that type errors are caught as errors and Python keeps track of types of variables
  • Dynamically typed means that variables do not need a type declared at their declaration and the type can be changed at runtime
  • A literal is literally a value
  • Boolean - Store flags, String - hold text, Float - decimal numbers
  • Separate them with a comma
  • The sides do not match up, there is a missing literal

Finding Types

Got some code and don't know what the types are?

Python has some functions to help with this.


In [1]:
type('am I your type?')


Out[1]:
str

Exercise

Try this with different types, how many can you find?

What happens when you do type([])?

type is an example of a built-in function, we will come back to these in a few sessions.

Strings

Strings in Python are unlike many languages you have seen before.

They can be:


In [ ]:
'single_quotes'

What do single quotes usually mean in most languages?

Strings wrapped in 'single quotes' are typically chars (single characters). Python does not have this type.

char yes = 'Y' //char (Python does not have this)
string no = "no" //string

What are chars used for? What does Python have instead?

Chars are typically used as single character flags, like a 'Y' or an 'N' as an answer to a question, or to hold an initial.

Anything text based can be stored in a string but flags can be represented as a 0 or 1 or even using a Boolean value,, which is easiest to check against.

What happens if you use a single quote for strings and you write the word don't in the string? Try it out now!

How do we get around that?

Escaping Strings

When you want to include special characters (like ') then it is always good to escape them!

Ever seen a new line written as \n? That is an example of escaping.

Escape Character

An escape character is a character which invokes an alternative interpretation on subsequent characters in a character sequence.

This is pretty much always \


In [ ]:
'isn't # not gonna work

In [ ]:
'isn\'t' # works a charm!

Strings II

If you do not want to escape every special character, maybe there is a better way?

"I am a string and I don't care what is written inside me"
"""I am a string with triple double quotes and I can
run across multiple lines"""

Double quotes is generally better as you do not have to escape these special characters.

Exercise

Declare a variable to store a boolean literal

Declare and instantiate a new variable that stores your age

The first one was a trick! Declaring a new variable means giving it no value!

The second one would be: age = 20

Reassigning Variables

It would not be fun to have to create a new variable for every thing you want to store, right?

As well as being a huge inconvenience, it is actually really inefficient.

age = 40
# 1 year passes
age = 41

Easy, right? By using the same variable name, it is now associated with your new value and the old value will be cleared up.

Printing

We have seen this print keyword thrown around alot, right? This is the best way to show some information. Especially useful if your script takes a long time to run!

E.g. print("stuff")


In [5]:
print("Got something to say?")
print("Use the print statement")
print("to print a string literal")
print("float literal")
print(3.14)
more_string = "or variable"
print(more_string)


Got something to say?
Use the print statement
to print a string literal
float literal
3.14
or variable

Exercise

Create a variable of type string and then reassign it to a float literal.

Now try adding a float literal to your variable

Operators

What is an operator? What do you remember from maths?

  • + (add)
  • - (subtract)
  • / (divide)
  • * (multiply)

There are more, but we will get to them!

Exercise

  • Add 3 and 4
  • Add 3.14 + 764 (what is the difference to the above answer?)
  • Subtract 100 from 10
  • Multiply 10 by 10
  • Add 13 to 'adios'
  • Multiply 'hello' by 5
  • Divide 10 by 3
  • Divide 10 by 3 but use 2 / (what happens?)

In Python 3, // is floor division and / is floating point division

Adding/Dividing/Subtracting Across Types


In [ ]:
float_type = 3.0
int_type = 5
print(int_type + float_type)

string_type = "hello"
print(string_type + float_type) # what is the error?

bool_type = True
print(string_type + bool_type) 

print(int_type + bool_type) # does this work? Why?

Multiplying Across Types

While Python is not happy to add/divide/subtract numbers from strings, it is more than happy to multiply


In [ ]:
float_type = 3.0
int_type = 5
print(int_type * float_type)

string_type = "hello"
print(string_type * int_type)

bool_type = True
print(string_type * bool_type) #why does this work?

print(int_type * bool_type)

Operating and Assigning

You may have a variable and want to change the value, this is reassigning, right?

year = 1998
year = 1999

There has to be an easier way. THERE IS. What is it?


In [ ]:
year = year + 1
year += 1

Exercise

Try this with all the operators you know.

Built in Functions

A function is a block of code that:

  • receives an input(s) (also known as arguments)
  • performs an operation (or operations)
  • Optionally, returns an output

Python has some built-in functions and we have used one already. What was it?

Functions - Print

print("Hello")

Format:

  • function_name
  • Open brackets
  • inputs (separated, by, commas)
  • Close brackets

Sometimes, inputs are optional. Not always. We will get to this.

Other Built in Functions

Exercise

Find out what the above functions do and use them in a script

What happens when you don't give each an argument?

Look up and write up definitions for the id and isinstance functions

str - converts an object to a string type len - prints the length of an object type - tells you the type of a literal or a variable int - converts a type to an integer

id - a unique id that relates to where the item is stored in memory isinstance - checks if an object if of the supplied type

Functions to Help You

dir


In [6]:
dir("")


Out[6]:
['__add__',
 '__class__',
 '__contains__',
 '__delattr__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__getnewargs__',
 '__getslice__',
 '__gt__',
 '__hash__',
 '__init__',
 '__le__',
 '__len__',
 '__lt__',
 '__mod__',
 '__mul__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__rmod__',
 '__rmul__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '_formatter_field_name_split',
 '_formatter_parser',
 'capitalize',
 'center',
 'count',
 'decode',
 'encode',
 'endswith',
 'expandtabs',
 'find',
 'format',
 'index',
 'isalnum',
 'isalpha',
 'isdigit',
 'islower',
 'isspace',
 'istitle',
 'isupper',
 'join',
 'ljust',
 'lower',
 'lstrip',
 'partition',
 'replace',
 'rfind',
 'rindex',
 'rjust',
 'rpartition',
 'rsplit',
 'rstrip',
 'split',
 'splitlines',
 'startswith',
 'strip',
 'swapcase',
 'title',
 'translate',
 'upper',
 'zfill']

help


In [5]:
help(int)
help("") 
help(1)


Help on class int in module __builtin__:

class int(object)
 |  int(x=0) -> int or long
 |  int(x, base=10) -> int or long
 |  
 |  Convert a number or string to an integer, or return 0 if no arguments
 |  are given.  If x is floating point, the conversion truncates towards zero.
 |  If x is outside the integer range, the function returns a long instead.
 |  
 |  If x is not a number or if base is given, then x must be a string or
 |  Unicode object representing an integer literal in the given base.  The
 |  literal can be preceded by '+' or '-' and be surrounded by whitespace.
 |  The base defaults to 10.  Valid bases are 0 and 2-36.  Base 0 means to
 |  interpret the base from the string as an integer literal.
 |  >>> int('0b100', base=0)
 |  4
 |  
 |  Methods defined here:
 |  
 |  __abs__(...)
 |      x.__abs__() <==> abs(x)
 |  
 |  __add__(...)
 |      x.__add__(y) <==> x+y
 |  
 |  __and__(...)
 |      x.__and__(y) <==> x&y
 |  
 |  __cmp__(...)
 |      x.__cmp__(y) <==> cmp(x,y)
 |  
 |  __coerce__(...)
 |      x.__coerce__(y) <==> coerce(x, y)
 |  
 |  __div__(...)
 |      x.__div__(y) <==> x/y
 |  
 |  __divmod__(...)
 |      x.__divmod__(y) <==> divmod(x, y)
 |  
 |  __float__(...)
 |      x.__float__() <==> float(x)
 |  
 |  __floordiv__(...)
 |      x.__floordiv__(y) <==> x//y
 |  
 |  __format__(...)
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getnewargs__(...)
 |  
 |  __hash__(...)
 |      x.__hash__() <==> hash(x)
 |  
 |  __hex__(...)
 |      x.__hex__() <==> hex(x)
 |  
 |  __index__(...)
 |      x[y:z] <==> x[y.__index__():z.__index__()]
 |  
 |  __int__(...)
 |      x.__int__() <==> int(x)
 |  
 |  __invert__(...)
 |      x.__invert__() <==> ~x
 |  
 |  __long__(...)
 |      x.__long__() <==> long(x)
 |  
 |  __lshift__(...)
 |      x.__lshift__(y) <==> x<<y
 |  
 |  __mod__(...)
 |      x.__mod__(y) <==> x%y
 |  
 |  __mul__(...)
 |      x.__mul__(y) <==> x*y
 |  
 |  __neg__(...)
 |      x.__neg__() <==> -x
 |  
 |  __nonzero__(...)
 |      x.__nonzero__() <==> x != 0
 |  
 |  __oct__(...)
 |      x.__oct__() <==> oct(x)
 |  
 |  __or__(...)
 |      x.__or__(y) <==> x|y
 |  
 |  __pos__(...)
 |      x.__pos__() <==> +x
 |  
 |  __pow__(...)
 |      x.__pow__(y[, z]) <==> pow(x, y[, z])
 |  
 |  __radd__(...)
 |      x.__radd__(y) <==> y+x
 |  
 |  __rand__(...)
 |      x.__rand__(y) <==> y&x
 |  
 |  __rdiv__(...)
 |      x.__rdiv__(y) <==> y/x
 |  
 |  __rdivmod__(...)
 |      x.__rdivmod__(y) <==> divmod(y, x)
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __rfloordiv__(...)
 |      x.__rfloordiv__(y) <==> y//x
 |  
 |  __rlshift__(...)
 |      x.__rlshift__(y) <==> y<<x
 |  
 |  __rmod__(...)
 |      x.__rmod__(y) <==> y%x
 |  
 |  __rmul__(...)
 |      x.__rmul__(y) <==> y*x
 |  
 |  __ror__(...)
 |      x.__ror__(y) <==> y|x
 |  
 |  __rpow__(...)
 |      y.__rpow__(x[, z]) <==> pow(x, y[, z])
 |  
 |  __rrshift__(...)
 |      x.__rrshift__(y) <==> y>>x
 |  
 |  __rshift__(...)
 |      x.__rshift__(y) <==> x>>y
 |  
 |  __rsub__(...)
 |      x.__rsub__(y) <==> y-x
 |  
 |  __rtruediv__(...)
 |      x.__rtruediv__(y) <==> y/x
 |  
 |  __rxor__(...)
 |      x.__rxor__(y) <==> y^x
 |  
 |  __str__(...)
 |      x.__str__() <==> str(x)
 |  
 |  __sub__(...)
 |      x.__sub__(y) <==> x-y
 |  
 |  __truediv__(...)
 |      x.__truediv__(y) <==> x/y
 |  
 |  __trunc__(...)
 |      Truncating an Integral returns itself.
 |  
 |  __xor__(...)
 |      x.__xor__(y) <==> x^y
 |  
 |  bit_length(...)
 |      int.bit_length() -> int
 |      
 |      Number of bits necessary to represent self in binary.
 |      >>> bin(37)
 |      '0b100101'
 |      >>> (37).bit_length()
 |      6
 |  
 |  conjugate(...)
 |      Returns self, the complex conjugate of any int.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  denominator
 |      the denominator of a rational number in lowest terms
 |  
 |  imag
 |      the imaginary part of a complex number
 |  
 |  numerator
 |      the numerator of a rational number in lowest terms
 |  
 |  real
 |      the real part of a complex number
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T


Help on int object:

class int(object)
 |  int(x=0) -> int or long
 |  int(x, base=10) -> int or long
 |  
 |  Convert a number or string to an integer, or return 0 if no arguments
 |  are given.  If x is floating point, the conversion truncates towards zero.
 |  If x is outside the integer range, the function returns a long instead.
 |  
 |  If x is not a number or if base is given, then x must be a string or
 |  Unicode object representing an integer literal in the given base.  The
 |  literal can be preceded by '+' or '-' and be surrounded by whitespace.
 |  The base defaults to 10.  Valid bases are 0 and 2-36.  Base 0 means to
 |  interpret the base from the string as an integer literal.
 |  >>> int('0b100', base=0)
 |  4
 |  
 |  Methods defined here:
 |  
 |  __abs__(...)
 |      x.__abs__() <==> abs(x)
 |  
 |  __add__(...)
 |      x.__add__(y) <==> x+y
 |  
 |  __and__(...)
 |      x.__and__(y) <==> x&y
 |  
 |  __cmp__(...)
 |      x.__cmp__(y) <==> cmp(x,y)
 |  
 |  __coerce__(...)
 |      x.__coerce__(y) <==> coerce(x, y)
 |  
 |  __div__(...)
 |      x.__div__(y) <==> x/y
 |  
 |  __divmod__(...)
 |      x.__divmod__(y) <==> divmod(x, y)
 |  
 |  __float__(...)
 |      x.__float__() <==> float(x)
 |  
 |  __floordiv__(...)
 |      x.__floordiv__(y) <==> x//y
 |  
 |  __format__(...)
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getnewargs__(...)
 |  
 |  __hash__(...)
 |      x.__hash__() <==> hash(x)
 |  
 |  __hex__(...)
 |      x.__hex__() <==> hex(x)
 |  
 |  __index__(...)
 |      x[y:z] <==> x[y.__index__():z.__index__()]
 |  
 |  __int__(...)
 |      x.__int__() <==> int(x)
 |  
 |  __invert__(...)
 |      x.__invert__() <==> ~x
 |  
 |  __long__(...)
 |      x.__long__() <==> long(x)
 |  
 |  __lshift__(...)
 |      x.__lshift__(y) <==> x<<y
 |  
 |  __mod__(...)
 |      x.__mod__(y) <==> x%y
 |  
 |  __mul__(...)
 |      x.__mul__(y) <==> x*y
 |  
 |  __neg__(...)
 |      x.__neg__() <==> -x
 |  
 |  __nonzero__(...)
 |      x.__nonzero__() <==> x != 0
 |  
 |  __oct__(...)
 |      x.__oct__() <==> oct(x)
 |  
 |  __or__(...)
 |      x.__or__(y) <==> x|y
 |  
 |  __pos__(...)
 |      x.__pos__() <==> +x
 |  
 |  __pow__(...)
 |      x.__pow__(y[, z]) <==> pow(x, y[, z])
 |  
 |  __radd__(...)
 |      x.__radd__(y) <==> y+x
 |  
 |  __rand__(...)
 |      x.__rand__(y) <==> y&x
 |  
 |  __rdiv__(...)
 |      x.__rdiv__(y) <==> y/x
 |  
 |  __rdivmod__(...)
 |      x.__rdivmod__(y) <==> divmod(y, x)
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __rfloordiv__(...)
 |      x.__rfloordiv__(y) <==> y//x
 |  
 |  __rlshift__(...)
 |      x.__rlshift__(y) <==> y<<x
 |  
 |  __rmod__(...)
 |      x.__rmod__(y) <==> y%x
 |  
 |  __rmul__(...)
 |      x.__rmul__(y) <==> y*x
 |  
 |  __ror__(...)
 |      x.__ror__(y) <==> y|x
 |  
 |  __rpow__(...)
 |      y.__rpow__(x[, z]) <==> pow(x, y[, z])
 |  
 |  __rrshift__(...)
 |      x.__rrshift__(y) <==> y>>x
 |  
 |  __rshift__(...)
 |      x.__rshift__(y) <==> x>>y
 |  
 |  __rsub__(...)
 |      x.__rsub__(y) <==> y-x
 |  
 |  __rtruediv__(...)
 |      x.__rtruediv__(y) <==> y/x
 |  
 |  __rxor__(...)
 |      x.__rxor__(y) <==> y^x
 |  
 |  __str__(...)
 |      x.__str__() <==> str(x)
 |  
 |  __sub__(...)
 |      x.__sub__(y) <==> x-y
 |  
 |  __truediv__(...)
 |      x.__truediv__(y) <==> x/y
 |  
 |  __trunc__(...)
 |      Truncating an Integral returns itself.
 |  
 |  __xor__(...)
 |      x.__xor__(y) <==> x^y
 |  
 |  bit_length(...)
 |      int.bit_length() -> int
 |      
 |      Number of bits necessary to represent self in binary.
 |      >>> bin(37)
 |      '0b100101'
 |      >>> (37).bit_length()
 |      6
 |  
 |  conjugate(...)
 |      Returns self, the complex conjugate of any int.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  denominator
 |      the denominator of a rational number in lowest terms
 |  
 |  imag
 |      the imaginary part of a complex number
 |  
 |  numerator
 |      the numerator of a rational number in lowest terms
 |  
 |  real
 |      the real part of a complex number
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

Homework

Complete sheet 2_Coding