Busy Developer's Guide to Python

ted@tedneward.com | Blog: http://blogs.tedneward.com | Twitter: tedneward | Github: tedneward | LinkedIn: tedneward

Objectives

In this talk, we shall...

Python

An Overview

Python

What is Python?

"Python is a programming language that lets you work quickly and integrate systems more effectively."- http://www.python.org

Python

What is Python?

"Python is an easy to learn, powerful programming language. It has efficient high-level data structures and a simple but effective approach to object-oriented programming. Python's elegant syntax and dynamic typing, together with its interpreted nature, make it an ideal language for scripting and rapid application development in many areas on most platforms."

Python

What is Python?

Getting Started

Getting the bits and stuff

Getting Started

Python is an open-source language

Getting Started

Python direct

Getting Started

Anaconda

Getting Started

Python command line

Getting Started

Python environment variables

Python Language

An Overview

Python Language

At a high level

Basics

Syntax, comments, types, oh my!

Basics

Source execution model

Basics

Hello, Python

#!/usr/bin/env python
# Say hello, Python
msg = "Hello, Python!"
    
print(msg)

Basics

Comments

Basics

Variables

Basics

Variables

num = 5
message = "This is a string"
this_is_a_really_long_variable = 0
x,y = 0,0
#uninitialized_variable  # error!

Basics

Stylistic/Idiomatic

Basics

Variable types

Basics

Variable types

Basics

Numbers

Basics

Numbers

div1 = 5 / 2      # 2.5
div2 = 5 // 2     # 2
square = 2 ** 2   # 4

Basics

Strings

Basics

Strings

Basics

Strings

str1 = "hello"
str2 = 'hello'
    
str3 = r"Long live metal \m/"
    
str4 = f"{str1}. I would like to say {str3}"
    
str5 = """
This is a here-doc. It can span lines.
It will continue going until we run into
the triple-quote again. It is often used
for documentation and simple formatting
purposes.
"""
    
str6 = "This" "is" "several" "strings"
    
str7 = str4[6:8]  # "is"

Basics

Tuples

Basics

Tuples

ted = "Ted", "Neward", 46
print(ted)                 # ("Ted", "Neward", 46)
charlotte = ("Charlotte", "Neward", 39)
first, last, age = ted
print(first)               # "Ted"

Basics

Lists

Basics

Lists

list1 = [1, 2, 3, 4, 5]
list2 = [1, "two", 3.0]
list3 = list1 + list2
firstlistelement = list1[0]
print(firstlistelement)
lastlistelement = list1[-1]
print(lastlistelement)

Basics

Sets

Basics

Sets

set1 = {1, 2, 3, 4, 5}
set2 = {1, 1, 2, 2, 3, 3, 4, 4}
print(set2)
    
set3 = {2, 4, 6}
set4 = {1, 4, 9, 16}
print(set1 & set2)
print(set1 - set2)
print(set1 | set3)

Basics

Dictionaries (Hashes)

Basics

Dictionaries (Hashes)

Basics

Dictionaries (Hashes)

dict1 = { "captain":"Antilles" }
dict1["admiral"] = "Ackbar"
k = dict1.keys()
v = dict1.values()
kv = dict1.items()
    
another_dict = dict(name="Ted",age=47)
print(another_dict)   # {'name':'Ted','age':47}

Flow Control

Branching, jumping, iterating, oh my!

Flow Control

Branching (If)

Flow Control

If

age = 45
if age > 50:
    print("You old!")
elif age < 18:
    print("Juvie!")
else:
    print("You not old!")
    
insult = "Boomer!" if age > 50 else "Millennial!"

Flow Control

Stylistic/Idiomatic

Flow Control

Pattern-matching (Match)

Flow Control

Match

http_message = ""
match status:
    case 400:
        http_message = "Bad request"
    case 404:
        http_message = "Not found"
    case 418:
        http_message = "I'm a teapot"
    case _:
        http_message = "Something's wrong with the internet"

Flow Control

If

# point is tuple
match point:
    case (0, 0):
        print("Origin")
    case (0, y):
        print(f"Y={y}")
    case (x, 0):
        print(f"X={x}")
    case (x, y) if x == y:
        print(f"Y=X at {x}")
    case (x, y):
        print(f"X={x}, Y={y}")
    case _:
        raise ValueError("Not a point")

Flow Control

Note: Python flexibility

Flow Control

Dictionaries of functions

import operator as op
calculator = { '+': op.add, '-': op.sub, '*': op.mul, '/': op.truediv }
    
left = int(input())
op = input()
right = int(input())
print(calculator[op](left, right))

Flow Control

Iteration (While)

Flow Control

While

x = 3
while x > 0:
    print("x is still more than 0")
    x = x -1
else:
    print("x is now " + str(x))

Flow Control

Iteration (For)

Flow Control

For

for c in range(10):
    print(c)
else:
    print("Can we see c?", c)
print("Can we still see c?", c)
    
message = "Python is interesting"
for ch in message:
    print(ch)
    
attendees = ["Marcel", "Roy", "Jeremy"]
for at in attendees:
    print(at)
    
my_first_tuple = "Ted", "Neward", 47
for t in my_first_tuple:
    print(t)

Flow Control

Stylistic/Idiomatic

Flow Control

Exception handling

Flow Control

Exception handling

Flow Control

Exception handling

Flow Control

Exceptions

try:
    bad_div = 1/0
except ZeroDivisionError:
    print("Silly boy; you can't do that")
else:
    print("Else!")
finally:
    print("Finally!")
    
try:
    print("In a new try block")
    raise Exception()
except Exception:
    print("We just raised this!")
print("Onwards we execute...")

Flow Control

Stylistic/Idiomatic

Flow Control

With

Functions

Reusable named behavior

Functions

Python comes with many functions

Functions

Some useful builtin functions

Functions

Some useful builtin functions

Functions

Built-in Functions

print("Hello, Python!")
print(dir(__builtins__))

Functions

User-defined functions

Functions

Defining functions

def sayHowdy():
    """This function says howdy and returns the same"""
    print("Howdy!")
    return "I said howdy"
    
response = sayHowdy()
print(response)           # "I said howdy"
print(sayHowdy.__doc__)   # "This function says..."

Functions

Default argument values

Functions

Default argument values

def sayGoodMorning(language="english"):
    if (language == "english"):
        return "Good morning!"
    else:
        return f"Sorry, I don't speak {language}"
    
print(sayGoodMorning())
print(sayGoodMorning("french"))

Functions

Keyword arguments

Functions

Keyword arguments

def saySomething(message="Hello", language="English", times=1):
    """Prints a message in a language a number of times"""
    for x in range(times):
        print(message + " (in " + language + ")")
    
saySomething(language="German", times=3, message="Good Morning")

Functions

Formal parameter collection

Functions

Formal parameters

def speak(**args):
    print(args)
    for key, value in args.items():
        print("argument " + str(key) + " = " + str(value))
    
speak(one="1", two="2", three="3")

Functions

Arbitrary argument list

Functions

Aribtrary argument lists

def myPrint(prefix, *rest):
    message = prefix
    for r in rest:
        message += " " + r
    print(message)
    
myPrint("Salutations")
myPrint("Salutations", "planet")

Functions

Functions are first-class citizens

Functions

Function literals

fn_lit = saySomething
fn_lit("Hello", "English", 2)

Functions

Lambda expressions (function literals)

Functions

Lambdas (aka closures)

messages = ["Hello", "Guten morgen", "Bonjour"]
def capIt(x):
    return x.upper()
print(capIt("hello"))   # "HELLO"
up_messages = map(capIt, messages)    # "HELLO", "GUTEN MORGEN", "BONJOUR"
up_messages2 = map(lambda x: x.upper, messages) # same as previous
    
add_one = lambda x: x+1     # same as def add_one(x): return x+1
result = (lambda x: x+1)(2) # 3

Functions

List comprehensions

Functions

Three ways to initialize a list of squares

squares1 = []
for x in range(10):
    squares1.append(x**2)
# or...    
squares2 = list(map(lambda x: x**2, range(10)))
# or...
squares3 = [x**2 for x in range(10)]

Functions

More Comprehensions

x = [2, 3, 4, 5, 6]
y = []
for v in x :
    y += [v * 5]        # y == [10, 15, 20, 25, 30]
    
y2 = map(lambda v : v * 5, x)
    
y3 = [v * 5 for v in x] # y3 == [10, 15, 20, 25, 30]

Functions

More Comprehensions

for v in x :
        if v % 2 :
            y += [v * 5]
    
y2 = map(lambda v : v * 5, filter(lambda u : u % 2, x))
    
y3 = [v * 5 for v in x if v % 2]

Functions

Generators

Functions

Generators

def generator_function():
    for i in range(10):
        yield i
for i in generator_function():
    print(i)
    
def fibonacci(n):
    a = b = 1
    for i in range(n):
        yield a
        a,b = b, a+b

Functions

Global references and keyword

Functions

Globals

player = "Fred"
    
def doSomething():
    #global player  # without this, it's an error
        # "UnboundLocalError: local variable 'player' referenced before assignment"
    player = player + " and Jed"
    print(player)
    
doSomething()

Classes

Combining state and behavior, oh my!

Classes

Pythonic classes

Classes

Definition

Classes

Basic syntax

class Person:
    """Someday this class will represent a human being"""
    
    # count is a "class variable" (static)
    count = 0
    
    # sayHello is a "class method" (static)    
    def sayHello():
        print("Hello, world!")
    
print(Person.count)
Person.sayHello()

Classes

Instantiation

Classes

"Static" vs "instance"

Classes

__init__

class Person:
    def __init__(self, fn, ln, a):
        self.firstName = fn
        self.lastName = ln
        self.age = a
    
    def code(self):
        print(self.firstName + " is coding, coding, coding...")
    
ted = Person("Ted", "Neward", 48)
ted.code()

Classes

Property members

Classes

Using property()

class Monster:
    def __init__(self, name):
        self._name = name
    
    def getname(self):
        return self._name
    
    def setname(self, value):
        self._name = value
    
    def delname(self):
        del self._name
    
    name = property(getname, setname, delname, "The Monster's name")
    
orc = Monster("Orc")
print("The " + orc.name + " attacks you!")

Classes

The property decorator

class Item:
    def __init__(self, name):
        self._name = name
    
    @property
    def name(self):
        return self._name
    
    @name.setter
    def name(self, value):
        self._name = value
    
    @name.deleter
    def name(self):
        del self._name
    
magicSword = Item("Sword +1")
print(magicSword.name + " is such a boring name")
magicSword.name = "Sting"  # Much better

Classes

Manipulation

Classes

Class manipulation

intern = Person("Joe", "Intern", 20)
intern.code()
    # "Joe is coding, coding, coding..."
    
print(dir(intern))
    # (Prints out a lot of methods, most of which we didn't define)
    
internCodeFunction = intern.code
internCodeFunction()
    # "Joe is coding, coding, coding..."

Classes

Method conventions

Classes

Method conventions

class Example:
    def __init__(self):
        print("Object constructor")
    def __del__(self):
        print("Object finalizer/destructor")
    def __repr__(self):
        print("Stringified representation of this object")
    def __eq__(self, other):
        print("Does this == other?")
        # See also __lt__, __le__, __gt__, __ge__, __ne__
    def __hash__(self):
        print("Generate a hash code for this object")
    def __bool__(self):
        print("returns True or False")

Classes

Stylistic/Idiomatic

Classes

Inheritance

Classes

Inheritance

class Student(Person):
    def study(self, subject):
        print(self.firstName + " is studying " + subject)

Classes

Access Control

Metaprogramming Python

Classes and types and oh my!

Metaprogramming Python

Python has a number of powerful features

Metaprogramming Python

Dynamic and functional nature

string = "This is a string"
print(dir(string))
number = 5
print(dir(number))
# do it on a builtin function, even!
print(dir(dir))
    
class FakeNumber:
    def __add__(self, other):
        return 0
    
fake = FakeNumber()
print(fake + 5)     # prints '5'
#print(fake - 5)    # error!

Metaprogramming Python

Dynamic and functional nature

# The dictionary: A poor man's class ...
person = { 'first': 'Ted', 'last' : 'Neward' }
# ... as long as it can take functions as values
person["speak"] = lambda: print(person['first'] + " " + person['last'])
    
# ... but it works!
person["speak"]()

Metaprogramming Python

Everything in Python is an object

Metaprogramming Python

Getting hold of the type object

print(type(3)) # <class 'int'>
print(type(['a', 'b', 'c'])) # <class 'list'>
print(type((1, 2, 3, 4))) # <class 'tuple'>
    
class Foo:
    pass
obj = Foo()
    
print(obj.__class__) # <class '__main__.Foo'>
print(type(obj)) # <class '__main__.Foo'>
print(obj.__class__ is type(obj)) # True

Metaprogramming Python

Decorators

Metaprogramming Python

Custom decorator

def restricted(func):
    def wrapper(*args, **kwargs):
        if 7 <= datetime.now().hour < 22:
            return func(*args, **kwargs)
        else:
            pass  # Hush, the neighbors are asleep
    return wrapper
    
@restricted
def say_whee():
    print("Whee!") # Only between 7 and 10!

Metaprogramming Python

Custom decorator: Timing functions

import functools
import time
    
def timer(func):
    """Print the runtime of the decorated function"""
    @functools.wraps(func)
    def wrapper_timer(*args, **kwargs):
        start_time = time.perf_counter()    # 1
        value = func(*args, **kwargs)
        end_time = time.perf_counter()      # 2
        run_time = end_time - start_time    # 3
        print(f"Finished {func.__name__!r} in {run_time:.4f} secs")
        return value
    return wrapper_timer
    
@timer
def waste_some_time(num_times):
    for _ in range(num_times):
        sum([i**2 for i in range(10000)])

Metaprogramming Python

Python can also define classes dynamically

Metaprogramming Python

Writing a class at runtime

RFoo = type('RFoo', (), {})
obj = RFoo()
print(obj)  # <__main__.RFoo object at ...?>
    
RBar = type('RBar', (RFoo,), dict(scotches=100))
obj = RBar()
print(obj.scotches)  # 100
print(dir(obj))
print(obj.__class__)
print(obj.__class__.__bases__)
    
Person = type('Person', (), {
  'first' : 'Ted', 'last' : 'Neward', 'speak' : lambda self: self.first + " " + self.last
})
ted = Person()
print(ted.speak())

Metaprogramming Python

Custom instantiation

Metaprogramming Python

Overriding __new__

class Foo:
    pass
    
def new(cls):
    x = object.__new__(cls)
    x.randomAttribute = 100
    return x
    
Foo.__new__ = new
    
f = Foo()
print(f.randomAttribute) # 100

Metaprogramming Python

Custom Metaclasses

Metaprogramming Python

Providing custom metaclass

class Meta(type):
    def __new__(cls, name, bases, dct):
        x = super().__new__(cls, name, bases, dct)
        x.randomAttribute = 100
        return x
    
class Foo(metaclass=Meta):
    pass
    
print(Foo.randomAttribute) # 100

Resources

Where to go for more

Online

Websites

Online

Deeper Python language

Credentials

Who is this guy?