Python

Python History

December 1989

Python 1.0 - January 1994

Python 2.0 - October 2000

+List Comprehensions

+Garbage Collection

+Nested Scopes (2.2)

+Type Unification (2.2)

+Generators (2.2)

Python 3.0 - December 2008

print => print()

 

"There should be one— and preferably only one —obvious way to do it"

Python Flavours

Brython

Python => Javascript

pyjs

Python => Javascript

RapydScript

Python => Javascript

CLPython

Python <=> Lisp

HotPy

High Performance Virtual Machine

IronPython

Python <=> .NET

Jython

Python <=> Java

PyMite

'flyweight', python-on-a-chip

PyPy

RPython + JIT == Speed!

tinypy

Python < 64Kb

CPython

The default

Getting Started

Installing

https://www.anaconda.com/

Running a program

$ python hello.py
Hello World!

REPL

$ python
Python 2.6.6 (r266:84292, Nov 21 2013, 10:50:32)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print('Hello World!')
Hello World!
>>>

IPython jupyter

$ ipython
Python 3.4.3 (default, Feb 25 2015, 21:28:45)
Type "copyright", "credits" or "license" for more information.

IPython 3.0.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]:

IDLE

$ idle

PyCharm

And more...

  • Visual Studio Code
  • Sublime Text
  • Vim
  • Atom
  • Jupyter Notebook
  • Eclipse + PyDev + LiClipse
  • GNU Emacs
  • Spyder
  • Thonny
  • ...

Jupyter Notebook

also runs Julia, and R...

Python Execution Model

Python Virtual Machine

find.pyc

draw.pyc

*.pyc

Python VM

OS

hardware

find.py

draw.py

*.py

Python interpreter

Python Paradigms

Imperative

Telling the "machine" how to do something, and as a result what you want to happen.

def print_even_numbers (list_of_numbers):
    for x in list_of_numbers:
        if x % 2 == 0:
            print x
        else:
            print False

print_even_numbers(natural_numbers)
natural_numbers = [0,1,2,3,4,5,6,7,8,9]

Functional

Telling the "machine" what you want to happen.

def even_number (x):
    return (x % 2) == 0

print(map(even_number, natural_numbers))
natural_numbers = [0,1,2,3,4,5,6,7,8,9]

Object Oriented

hello.py

# Python 2
print 'Hello World!'

hello.py

# Python 3
print('Hello World!')

whitespace counts

whitespace counts

do:

no;

4 spaces, no tabs

80 chars/line

 

 

Read PEP 8

Python Data Types

Numbers

  • int
  • float
  • complex

Numbers


x = 40 + 42.67
y = int(67.879)
z = float(12)

print(x + y) # sum of x and y

print(x - y) # difference of x and y

print(x * y) # product of x and y

print(x / y) # quotient of x and y

print(x // y) # floored quotient of x and y

print(x % y) # remainder of x / y

print(abs(x)) # absolute value or magnitude of x

print(int(x)) # x converted to integer

Strings

  • Strings are a list of characters.
  • A single character is a string (list) of length 1.
  • Use len() to check for length
name = 'python'

list(name)  # ['p', 'y', 't', 'h', 'o', 'n']
name + name  # 'pythonpython'
name * 3  # 'pythonpythonpython'
len(name)  # 6

Strings

  • string[n] gives the character at the nth position.

  • Since strings are lists, you can iterate over them

# Get character at position n, 0-based
name[1]

# Iterate over a string
for character in name:
    print(character)

Strings

  • Membership tests
name = 'python rocks!'
'p' in name # True
'z' in name # False
'rock' in name # True

Strings

  • Use string variables
print('My name is %s and my weight is %f kg.' % (name, 78.8))

Strings

  • multi-line strings with triple quotes
str = """ The big brown fox
quickly jump ed over the wall
and ran away.
"""

Strings

  • Raw strings
print(r"Use \n fox new line")

Strings

  • f-strings (PEP 498)
company = "Kontali"
print(f"Welcome to {company}!")

Strings

  • re is for regex
  • .join() joins
import re
m = re.search('(?<=-)\w+', 'spam-egg')
m.group(0)  # 'egg'

filename = 'foo'
extension = 'log'
'.'.join([filename, extension])  # 'foo.log'

Lists

  • A list is a mutable collection of heterogenous items.

emptyList = []

['Hello'] * 4  # ['Hello', 'Hello', 'Hello', 'Hello']

languages = ['C', 'C++', 'Java', 'JavaScript', 'Elixir']

languages.append(['F#', 'C#']) # adds a list to the list

languages.extend(['Kotlin', 'TypeScript', 'Python']) # extends the list with the contents of a list

Lists

  • Membership tests
'Python' in languages # returns True
'python' in languages # returns False

Lists

  • Sort with sorted()
beatles = ['McCartney', 'Lennon', 'Starr', 'Harrison']
sorted(beatles)
sorted(beatles, reverse=True)

Lists

  • Python lists are heterogenetic. (data of different types can be stored.)
mixed_list = [12, 'Oslo', 67.65, complex(34, 56)]

List comprehensions

squares = []
for x in range(10):
    squares.append(x**2)
squares = [x**2 for x in range(10)]
  • Make new lists based on some condition

List comprehensions

# returns square of 0-9 if number is even
squares = [x**2 for x in range(10) if x %2==0 ]
  • if and for
# combines the elements of two lists if they are not equal
notEqualCombinations = [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]

Tuples

  • A tuple is a list, but an immutable list
myList = ['a', 'b', 'mpilgrim', 'z', 'example']
myTuple = ('a', 'b', 'mpilgrim', 'z', 'example')

myList[3] = 'c'  # ['a', 'b', 'mpilgrim', 'c', 'example']
myTuple[3] = 'c'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Named Tuples

  • A namedtuple is a tuple with names
from collections import namedtuple

Station = namedtuple("Station", "id, city, state, lat, long")
tokyo = Station(999, "Dallas", "TX", "32.79°N", "96.77°W")
tokyo
# Station(id=999, city='Dallas', state='TX', lat='32.79°N', long='96.77°W')
tokyo.city
# 'Dallas'

import json
json.dumps(tokyo._asdict())
#'{"id": 999, "city": "Dallas", "state": "TX", "lat": "32.79\\u00b0N", "long": "96.77\\u00b0W"}'

Dictionaries

  • A dict is a mutable associative array (a.k.a. 'map')
  • Think of it as an unordered set of key:value pairs
europe = {'sweden':'stockholm', 'norway':'oslo', 'finland':'helsinki', 'denmark':'copenhagen'}
europe['france'] = 'paris'
europe.get('norway')

Dictionaries

  • Membership tests
'sweden' in europe # returns True
'china' in europe # returns False

Dictionaries

  • Define your own sorting method
movies = {'The Game of Shadows': [129, 'Mystery', 'Guy Ritchie', 2011],
          'The Dark Knight': [126, 'Action', 'Christofer Nollan', 2008],
          'Sherlock Holmes': [128, 'Mystery', 'Guy Ritchie', 2009],
          'Interstellar': [169, 'SciFi', 'Christofer Nolan', 2014]}

sorted(movies) # returns movies sorted by title

def get_sort_key(value):
    return value[3]

sorted(movies.values(), key=get_sort_key) # returns movies sorted by year

Dict Comprehensions

  • Make new dicts based on some condition
movies = {'The Game of Shadows': [129, 'Mystery', 'Guy Ritchie', 2011],
          'The Dark Knight': [126, 'Action', 'Christofer Nollan', 2008],
          'Sherlock Holmes': [128, 'Mystery', 'Guy Ritchie', 2009],
          'Interstellar': [169, 'SciFi', 'Christofer Nolan', 2014]}

newMovies = { key: value for key, value in movies.items() if value[3] > 2010 }

Python Idioms

Loops

index = 0
while index < len(names):
    print (names[index])
    index+=1
for name in names:
    print name
names = ['Larry', 'Moe', 'Curly']

Enumerate

count = 0
for name in names:
    print(count, name)
    count += 1
for count, name in enumerate(names):
    print(count, name)
names = ['Larry', 'Moe', 'Curly']
for count, name in enumerate(names, start=1):
    print(count, name)

String Chaining

my_long_text = "We are no longer the knights who say Ni! We are now the knights who say ekki-ekki-ekki-p'tang-zoom-boing-z'nourrwringmm!"
my_long_text = ("We are no longer the knights who say Ni! "
                "We are now the knights who say ekki-ekki-"
                "ekki-p'tang-zoom-boing-z'nourrwringmm!")

Duck Typing

if 'x' in d and isinstance(d['x'], str) and d['x'].isdigit():
    value = int(d['x'])
else:
    value = None
try:
    value = int(d['x'])
except (KeyError, TypeError, ValueError):
    value = None
d = {'x': '5'}

Importable and Executable

if __name__ == '__main__':
def main():
 print('Doing stuff in module', __name__)


if __name__ == '__main__':
 print('Executed from the command line')
 main()

Modules

Modules

  • Python files that can contain variables, functions and classes.
  • Can be used in another python file by using ”import” and ”from”.
  • Import gives access to all in the imported module. 
  • From allows for the selected usage.​

Modules

# utility.py

pi = 3.14285

def get_circle_area(radius):
     return pi * radius**2
# circle.py

import utility

print(utility.pi)
print(utility.get_circle_area(10))
# circle.py

from utility import get_circle_area

print(get_circle_area(10))

to use everything in utility.py:

to use only a specific method from utility.py:

Objects

Object References

  • All data in a Python program is represented by objects or by relations between objects

Object References

int a = 1;

Not Python:

Object References

int a = 2;

Not Python:

Object References

int b = a;

Not Python:

Object References

a = 1

Python:

Object References

a = 2

Python:

Object References

b = a

Python:

Classes and Objects

Classes and Objects

class Salmon:

    animal_type = "fish"		# Class variable
    location = "ocean"			# Class variable

    # Constructor method with instance variables name and age
    def __init__(self, name, age):
        self.name = name
        self.age = age


def main():
	
    sammy = Salmon("Sammy", 4)
    print(f'{sammy.name} is a salmon that lives in the {sammy.location}')

    stevie = Salmon("Stevie", 3)
    print(f'Another salmon is {stevie.name} who is {stevie.age} years old')


if __name__ == "__main__":
    main()

Functions

Functions

  • Setting default values
def get_full_name(fname, lname='Andersson'):
    return fname + ' ' + lname

get_full_name('Nisse')
get_full_name('Nisse', 'Pettersson')

Functions

  • Passing arguments
def add(a, b, c, d):
    return a + b + c + d

add(4, 7, 8, 2)   # Values are assigned by positions
add(b=42, c=45, d=87, a=34)    # Values are assigned by argument names or keyword names
add(32, 67, d=66, c=12)    # Mix of the above

Functions

  • Passing arbitrary arguments
def foo(*args):
      print(args)	# args is a tuple that collects all the incoming arguments

foo(34, 56, 78)

Functions

  • Passing arbitrary key:value arguments
def foo(**kwargs):
     print(kwargs)	# kwargs is a dictionary. This works only for keyword-value based calls

foo(fname='John', lname='Doe')

Functions

  • Hybrid arguments
def foo(a, b, *args, **kwargs):
    print(a)
    print(b)
    print(args)
    print(kwargs)

Pass by value or reference?

  • Neither. Python uses pass-by-object-reference
  • Depends on mutable or imutable object

Pass by value or reference?

  • Immutable object
def change_value(value):
    value = 42

some_value = 50
print(some_value) # 50
change_value(some_value)
print(some_value) # 50

Pass by value or reference?

  • Mutable object
def change_list(some_list):
    some_list.append(42)

another_value = [1, 2, 3, 4, 5]
print(another_value) # [1, 2, 3, 4, 5]
change_list(another_value)
print(another_value) # [1, 2, 3, 4, 5, 42]

Special

Function Constructs

Generator Functions

  • Yield saves state and returns a value when next() is called
def get_even(number):
    while True:
        if number % 2 == 0:
            yield number
        number += 1
>>> generator = get_even(33)
>>> generator.next()
34
>>> generator.next()
36

Decorator Functions

def heading(func):
   def wrapper(name):
       return "<h1>{0}</h1>".format(func(name))
   return wrapper


@heading
def greet(name):
   return "Hello {0}, i hope you are well!".format(name)

print greet("John Doe") # <h1>Hello John Doe, i hope you are well!</h1>

You can also execute the wrapped function, giving you the ability to do something before and after the function executes.

Functional Programming

Functional Programming

  • Map
items = [1, 2, 3, 4, 5]

def sqr(x):
    return x ** 2

list(map(sqr, items)) # [1, 4, 9, 16, 25]

Map takes a function and a collection of items. It makes a new, empty collection, runs the function on each item in the original collection and inserts each return value into the new collection. It returns the new collection.

Functional Programming

  • Reduce
items = [0, 1, 2, 3, 4]

def add(a,x):
    return a + x

sum = reduce(add, items) # 10

Reduce takes a function and a collection of items. It returns a value that is created by combining the items.

Functional Programming

  • Filter
items = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]

def negative(x):
    if x < 0:
        return x

list(filter(negative, items)) # [-5, -4, -3, -2, -1]

Filter takes a function and a collection. It returns a collection of every item for which the function returned True.

Functional Programming

  • Higher order functions
def twice(function, x):
    return function(function(x))


def f(x):
    return x + 3


twice(f, 7)  # 13

higher-order functions are functions that can accept other functions as arguments and return functions to the caller.

Functional Programming

  • Anonymous functions (a.k.a. Lambda functions a.k.a. Literal functions)
def square(x):
    return x**2

square(8)  # 64

(lambda x: x**2)(8)  # 64

An anonymous function is a function definition that is not bound to an identifier.

To Python or not to Python?

Python?

def fizzbuzz(number):
    if number % 3 == 0 and number % 5 == 0:
        return 'FizzBuzz'
    elif number % 3 == 0:
        return 'Fizz'
    elif number % 5 == 0:
        return 'Buzz'
    else:
        return number

for number in range(1, 101):
    print fizzbuzz(number)

Java?

import sys

class Value(object):
    def __init__(self,value):
        self.setValue(value)

    def setValue(self,value):
        self.value = value

    def getValue(self):
        return self.value

    def toString(self):
        return self.getValue().__str__()

class FizzBuzz(object):
    def __init__(self, n):
        if n % 15 == 0:
            value = 'FizzBuzz';
        elif n % 3 == 0:
            value = 'Fizz';
        elif n % 5 == 0:
            value = 'Buzz';
        else:
            value = str(n);
        self.setValue(value);

    def setValue(self,value):
        self.value = Value(value);

    def getValue(self):
        return self.value;

class FizzBuzzRunner(object):
    def __init__(self, n):
        self.setN(n)

    def setN(self, n):
        self.n = n

    def run(self):
        for i in range(1,self.n):
            sys.stdout.write(FizzBuzz(i).getValue().toString()+'\n');

if __name__ == '__main__':
    n = 101;
    FizzBuzzRunner(n).run()

C?

def main():
    i = 0;
    value = '';

    while i < 100:
        i += 1
        if i % 15 == 0:
            value = 'FizzBuzz';
        elif i % 3 == 0:
            value = 'Fizz';
        elif i % 5 == 0:
            value = 'Buzz';
        else:
            value = str(i);
        print value;

    return 0;

main();

Clojure?

def fizzbuzz(n):
    return 'FizzBuzz' if n % 3 == 0 and n % 5 == 0 else None

def fizz(n):
    return 'Fizz' if n % 3 == 0 else None

def buzz(n):
    return 'Buzz' if n % 5 == 0 else None

def fizz_andor_maybenot_buzz(n):
    print fizzbuzz(n) or fizz(n) or buzz(n) or str(n)

map(fizz_andor_maybenot_buzz, xrange(1, 101))

Lisp?

fizzbuzz = lambda n: 'FizzBuzz' if n % 3 == 0 and n % 5 == 0 else None
fizz = lambda n: 'Fizz' if n % 3 == 0 else None
buzz = lambda n: 'Buzz' if n % 5 == 0 else None
fizz_andor_maybenot_buzz = lambda n: fizzbuzz(n) or fizz(n) or buzz(n) or str(n)

print reduce(lambda m,n: m+'\n'+n, map(fizz_andor_maybenot_buzz, range(1, 101)))

Testing

Unit Testing

# utility.py

class Utility:

    def add(self, a, b):
        return a+b

    def sub(self, a, b):
        return a-b

    def multiply(self, a, b):
        return a*b

Unit Testing

# test_utility.py

import unittest
from utility import Utility


class TestUtility(unittest.TestCase):

    util = None

    def setUp(self):
        self.util = Utility()

    def tearDown(self):
        self.util = None

    def test_add_with_positive_values(self):
        a = 10
        b = 20
        expected_value = 30
        actual_value = self.util.add(a, b)
        self.assertEquals(expected_value, actual_value)

    def test_add_with_positive_and_negative_values(self):
        a = -10
        b = 20
        expected_value = 10
        actual_value = self.util.add(a, b)
        self.assertEquals(expected_value, actual_value)

if __name__ == "__main__":
    unittest.main()

PEPs

PEP 8

Style Guide for Python Code

PEP 257

Docstring Conventions

PEP 3132

Extended Iterable Unpacking

Python Gotcha's

Forgetting Parenthesis

# Correct
foo.close()
# Incorrect, but no error :(
foo.close

GIL

The global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once

Mutable Default Arguments

Python’s default arguments are evaluated once when the function is defined, not each time the function is called. This means that if you use a mutable default argument and mutate it, you will and have mutated that object for all future calls to the function as well.

Late Binding Closures

def create_multipliers():
    return [lambda x : i * x for i in range(5)]


for multiplier in create_multipliers():
    print(multiplier(2))
# expected
0
2
4
6
8
# actual
8
8
8
8
8

whenever any of the returned functions are called, the value of i is looked up in the surrounding scope at call time. By then, the loop has completed and i is left with its final value of 4.

Dependencies

  • pip
  • easy_install
  • virtualenv

 

  • pipenv

Nice Libs

Requests

import requests

response = requests.get('https://www.ssb.no/eksport/tabell.csv?key=435931')

Numpy

For all your N-dimensional array needs...

Pandas

import pandas as pd
df = pd.read_json('http://www.openfisheries.org/api/landings.json')
df.head()

Matplotlib

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(19680801)
data = np.random.randn(2, 100)

fig, axs = plt.subplots(2, 2, figsize=(5, 5))
axs[0, 0].hist(data[0])
axs[1, 0].scatter(data[0], data[1])
axs[0, 1].plot(data[0], data[1])
axs[1, 1].hist2d(data[0], data[1])

plt.show()

Let's play!

Set the stage...

from IPython.core.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))

Check the weather..

import requests

city = 'name of your city'
resp = requests.get(f'https://wttr.in/{city}')
print(resp.text)

Download a data-set

https://www.scrfa.org/database/Search-Results.php

new notebook...

import pandas as pd
from pandas_profiling import ProfileReport

data = pd.read_csv('data/fish.csv')

profile = ProfileReport(data, title="Sample Report")

profile

Zen of Python

(PEP 20)

import this

Power of Python

(xkcd)

import antigravity

Tadaaa !

Python

By maderskog

Python

  • 562