Python Handbook
Reminders and code snippets for creating Python3 programs.
Development Tools
IDEs
- Jupyter: from terminal
jupyter notebook
, install instructions - Microsoft Visual Studio Code: cross-platform IDE with plugins support for many languages, among which Python
The Language of Python
Vocabulary
- Everything in Python is an object.
- All functions are first-class objects and end with ()
- Methods are functions specific to instance. Instances have different types.
- A method’s signature is the number and types of parameters a method needs to run. Use help() to see a methods signature.
- Type is the the class of an object
- value, what the object holds. Compared with ==
- id, location in memory, compared with is.
- code smells, when you write something unpythonic.
- magic numbers, are numerical values put in the code without a variable. They should be avoided, instead assign them to a variable.
- # comment, marked with a # and only meant to clarify for hoomans
Python Naming Conventions
- Functions, variables, and module names are written with snake_case not camelCase or kebab-case.
- Class names written with CamelCase
- packages get no underscore between words
- constants are written in ALLCAPS
The REPL
This is where the action starts. One liners and simple functions can be written and tested immediately. REPL is an acronym for Read-eval-print-loop. Meaning it will read a command, evaluate it, print it, and then loop to be ready for another command. In this handbook, when a command is written in the REPL it is indicated with »>.
Assuming you have correctly installed Python, to start the REPL use
$ python3
To navigate to different directories in the REPL use
import os # imports are explained under the Library Heading
os.chdir('full/path/to/dir')
os.getcwd() # To see which directory the REPL is looking in
Execute a file in your REPL
exec(open('FILE').read())
Helpful methods
dir()
Gives a directory of all the attributes a given object has. These attributes can be methods aka functions specific to an object. The attributes that start with __ are the special methods, Dunder methods or magic methods. Special methods are used by special operators such as + or %. For information look at SPECIALMETHODS under help().
help()
This could and maybe even should be the only source of knowledge for Python students. For information about any method use help(OBJECT.METHODNAME) for a brief text about what that method does. For example
help('TexT'.swapcase)
tells you what swapcase does. Instead of creating the instance like in the example I can write the type, str, int, float and so on or use the variable I labeled my instance as. Note that writing
help(30.real)
produces an error because with number Python assumed I was creating a float and just did so incorrectly.
help() also shows a methods signature. Between the parenthesis the suffix is required and the information between the square brackets is optional.
import pdb; pdb.set_trace()
Use this at the start of programs you want to debug. This runs the program through an interface similar to the REPL so you can debug it. Use h to see the list of available commands.
A Little About Objects
Truthy or falsey
Objects can be truthy or falsey. Empty strings are falesy, 0 is falsey, empty lists are falsey.
See if something is truthy or falsey with bool(OBJECT)
Containers
Every object in python is given an unchanging id, you can see this with id class.
id(name)
Containers hold multiple objects
Lists are mutable object holders. You can add with .append
or remove with .remove
even insert with .insert
.
If you run a function on a list like sort(old_list)
you will get a new list, but if your the method old_list.sort
it will change your existing list.
create a new list with name_of_list = []
.
When inserting to the list named_list.insert(0, 'hello')
where 0 is the which index and ‘hello’ was the what. If inserting from the start you better use collections.deque as it uses a different data structure
list('Adam') # turns sequence of characters into separate elements in a list
tuples are immutable object holders. there are 3 ways to create tuples, but the Pythonic way is
p = ('first_element', 'look commas', 'party in the tuple')
Tuples are used as keys in dictionaries and use less memory than lists, because tuples are immutable. Generally used to return information from a function.
Sets are mutable unordered collection without duplicates. Look up operations are very cheap for sets as they use hash functions. Sets do not keep elements in order but the “in” operator works fast on sets than lists.
sets are created with filled curly brackets {2,1} or directly from the set class
integer_list = [0,1,1,2,2,3,4,9,5]
integer_set = set(integer_list)
integer_set = {1,2}
dir(Class) # lists methods in a class where Class is the name of the class.
Slicing Lists
My_list=[1,2]
Lists are mutable
l1 = ['apple', 'pear', 'grapes', 'banana']
print(l1)
print(l1[:1])
Slice a list is done with the list[start:stop] notation.
The number start is which index you start your new list from.
Builtin Methods, Classes, and Libraries
F-strings
New in Python 3 are f-strings.
name = "World"
F"Hello, {name}."
List Comprehension
Lets you look inside a list in a list.
Dictionaries
are highly optimized containers with keys and values. Passing a tuple in would the 0 index a key and the 1 value the value. Dictionaries are indicated with curly brackets { }. You can add keys and values to existing dictionaries. You can pull values directly out of the dictionary just by calling the key Dictionary is a 2 column table, where each key has one value. If you want more columns, you need, for example, a list of dictionaries.
Dictionaries are used for Classes, namespaces, and modules.
Example dictionary
my_dict = {'name': 'Adam', 'surname': 'Smith'}
Pulling Data out of containers (lists, tuples, strings)
Indexing is for specific elements slicing is for sub-sequences
a negative index -1 counts from the back, it’s a[len(a)-X] is a[-X]
you can add indexing to your own classes with .getitem
Slicing can also have a stride, so take every second, or ever third item in the third field
Loops
instead of range and len to loop through a loop use the built in enumerate function.
Functions
You can run help and dir on the functions you create yourself and get useful info out. You write the function definition. You name a function so that you can invoke it by calling the name. then you have the block of code that says what the function does. Add a docstring to make the help of the function more useful. Docstrings sit just after the def line in “““triple quotes "””
When naming your own functions “Function names should be lowercase, with words separated by underscores as necessary to improve readability. Variable names follow the same convention as function names. " From https://peps.python.org/pep-0008/
Built in functions
Full list at Python docs
- repr() useful when debugging. Creates a printable representation of an object. A class can specify what this function returns by defining a _repr_ method.
Performance Notes
result += item
is faster than result = result+item
because it looks for result only once
Files in and Out
The function to open a file is called open
open(filename, mode='r', buffering=-1, encoding = None, errors=None, newline=None, closefd=True, open=None)
To the list of methods available to a file, remember to use dir(OBEJCTTYPE OR OBJECT INSTANCE)
Then to get more information about individual methods get the help for the method with in this case
help(passwd_file.close)
In Windows use r"C:\test"
when needing to use the backspace. r is for raw, because \ is a Python escape character
passwd_file.readline()
to read one line or
listoflines = passwd_file.readlines()
to read the files into a list
with open('/tmp/names3.txt', 'w') as fout3:
fout3.write('Ringo\n')
With closes the file after the block is run. This is the same as
fout3 = open('/tmp/names3.txt', 'w')
fout3.write('Ringo\n')
fout3.close()
the write() method is write a string, the writelines() method is to write a list of strings
Argparse Library
Positional arguments are when the position of argument deters it’s function
For ls, -l is an optional arguement that changes how the command behaves. … –help provides information about how to use the ls command. It doesn’t do anything in windows though
Just importing and using argparse gives –h, –help
Argparse.ArgumentParser() has methods:
Add_argument(“argument_name”)
Parse_args() : are the arguments that I have added and makes them accessible with the dot notation.
Argparse creates a variable for each argument with the name of the argument. The details magic, meaning you don’t need to know them to use argparse at this level.
Into add_argument we can add a help text as a parameter. It’ll look like this .add_argument(“argument_name”, help=“Here I explain how argument_name is used.”)
By default all arguments passed in are treated as strings. We can specify the type with
.add_argument(“argument_name”, help=“Here I explain how argument_name is used.”, type=int)
So instead of relying on position, we want to name our arguments making the order in which are passed irrelevant and require they are named. This is the magic of starting the argument with –
.add_argument(”–now_optional_and_require_name”)
Unicode Fun
Encode a unicode string to a byte string for storage. Then you decode the byte string to be readable.
We have unicode of variable length so that don’t take up so much memory.
For 4 digit unicode characters \u26F4
More than 4 \U0001F6A2
where you pad until 8 digits.
Or you can write the name \N{FERRY}
or \N{ferry}
You can then encode the characters into ASCII or languages, but mostly only for legacy purposes.
Classes
Except keywords and variable names everything is an object. All objects belong to a class. A class defines what objects can hold and what methods can be used to alter them. An instance is an occurrence of a class.
A class consists of, a name, docstring, class attributes, and def statements (functions in classes are called methods). The variable are called attributes. Classes are named using CamelCasing.
There is a special method in classes called __init__(def, id)
. It is a constructor, that creates the class. The body of the constructor you give the class the unique attributes each instance of it will have.
For example, the attributes in the class Car may be: ```init(self, brand, horsepower, zero_to_sixty, doors)
A car class:
class Car:
def __init__(self,brand,horsepower,zero_to_sixty,price):
self.brand = brand
self.horsepower = horsepower
self.zero_to_sixty = zero_to_sixty
self.price = price
# give a string representation of your object
# instead of memory address such as <__main__.Car object at 0x108e006d0>
def __repr__(self):
return f"Car (brand: {self.brand}, horsepower: {self.horsepower}, Zero to sixty: {self.zero_to_sixty}, Price: {self.price}"
Methods have a self parameter because you are passing the class to the parameter.
Protected methods are methods that are only to be accessed from within the class. Protected methods start with a _. These should not be called from outside the class and may be removed in future versions of the class.
Subclasses and Superclasses
subclasses inherent from and overrides superclass properties.
class SoyLatte(Latte)
creamer = soy_milk
subclasses do not have a __init__
method, Python looks to the super class
Exceptions
There are several ways to deal with exceptions.
- “Look before you leap” (LBYL) Can be done with if statements, to check if result is invalid do the else. Not guaranteed to work as variables and external dependencies can change during program execution.
numerator = 10
divisor = 0
if divisor != 0:
result = numerator / divisor
else:
result = None
Need to make my own examples
- “Easier to ask for forgiveness than permission (EAFP) This is the try…expect blocks, and the most used method to avoid errors.
numerator = 10
divisor = 0
try:
result = numerator / divisor
except Zero DivisionError as e:
result
e is the instance of the error, making it accessible as a variable. Only put one line in the try statement so you can be specific in dealing with the error occurrence.
Server type applications process_input
and log_error(e)
serve as placeholders
The three error handling guidelines, quoted from IGTP.
- gracefully handle errors you know how to handle and can reasonable expect
- Do not silence exceptions that you cannot handle or do not reasonably expect
- Use global exception handler to gracefully handle unexpected errors
With tuples an exception statement can catch more then one exception type except (TypeError, ValueError):
finally
for code that will run whether or not the exception was met. Used for freeing up external resources if the program fails.
Try and finally have a code smell, so look into using context managers
Collections
namedtuple
instead of having to use index values to refer to tuple elements you can use strings
Libraries
To use a library load it into your namespace.
You can check if a variable is in your library with
>>>'sin' in dir()
Importing a library is the creation of a variable that points to the function in that library. If you import the whole library then the functions are not in your namespace you will need specify that you are using the library. See example below.
import os
os.getcwd() # To show what directory the console is running
os.chdir() # Change the directory you are in
Help also works here, so you can use >>> help(os.getcwd)
When importing specific functions, you will not need to specify the library to look in when running the function.
from os import getcwd, chdir
Use parenthesis if importing functions over multiple lines
from os import (getcwd,
... chdir)
You can choose the name of the variable you are using to call the library.
from os import getcwd as cwd
import numpy as np
import pandas as pd
star imports from os import *
import all the functions, class definitions and variables in the namespace. This is not recommended because when importing multiple libraries the name may overwrite each other.
Some libraries are nested so you need specify the full path the functions you want to reach
from xml.dom.minidom import parseString
Be careful of circular imports, where modules mutually import one and other.
Modules and Packages
A library is made of Modules that can be grouped into Packages
Packages are directories and require an __.init__.py
file to be a package.
module names are short, lowercase and may have underscores packages names are short, lowercase and without underscores
You can set a PYTHONPATH if your libraries are not installed and you need to specify where your libraries are.
You can check under which paths your python REPL looks for libraries with
import sys
sys.path
In rare cases you may want to manually add a python library to your program. This can be done by either adding the path to PYTHONPATH before launching or to the sys.path after having run the program
$ PYTHONPATH = /path/to/library python3
or
import sys
sys.path.append('/path/to/library') # You should write the full path, but relative to where you are also works
Datetime
datetime.today() is a datetime.datetime object
different datetime objects can create different objects datetime.datetime and datetime.date are two different object types
can do math with dates
start_time = datetime.today()
initial_end_time = timedelta(hours=1)
start_datetime.replace(hour=8)
what is time.time() ? It gives the time in seconds from the epoch.
PYTZ Library
pytz brings the Olson tz database into Python. This library allows accurate and cross platform timezone calculations using Python 2.4 or higher. Example code of converting datetimes to different timezones
import pytz
from datetime import datetime
from pytz import timezone
input_time="2023-03-23T03:00"
utc = pytz.utc
cet = timezone('Europe/Copenhagen')
print(cet.zone)
print(utc.zone)
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
start_datetime=datetime.fromisoformat(input_time)
cet_start_datetime=cet.localize(start_datetime)
utc_start_datetime=cet_start_datetime.astimezone(utc)
print(F"Not pickled: {start_datetime}")
print(F"Pickeled with CET datetime: {cet_start_datetime.strftime(fmt)}")
print(F"Converted to UTC datetime: {utc_start_datetime.strftime(fmt)}")
sched I create a schedule with s.enter(10,1,action) then I run the schedule
s.empty() shows if there are any events pending execution s.run() runs the created schedule s.cancel() I can can cancel events, this I can use when on breaks
Python Library Notes
- See BeautifulSoup Handbook
Writing and Sharing Programs
Let’s move out of the REPL and start writing programs allows for complicated tasks to be completed. Here is where an IDE really starts being useful, as well as using version control to keep track of your work. I have always used Git, therefore this guide also uses Git, github to be more specific. Being familiar with version control and an IDE are important skills, however beyond the scope this guide.
Virtual Environments
When working in terminal it is recommended to use virtual environments (venv) as this will not change your base python installation and make it easy to share the libraries needed for a program. My preferred location for python is ~/Library/venvs to keep them out of my repository.
$ python3 -m venv <venv folder>
With a virtual environment you can collect all the installs you made to have your program run into a requirements.txt file. This can then be shared with others so they can recreate your environment and run your programs. This is safer than copying your venv folder over because they may be running a different version of Python or a different OS.
$ pip freeze > requirements.txt # to list your installed libraries in a file
$ pip install -r requirements.txt # to install your libraries from requirements.txt
To activate a virtual environment
MacOS
$ source PATH_TO_VENV_FOLDER/bin/activate
Powershell
./PATH_TO_VENV_FOLDER/source/activate
To update pip on macOS. python3 -m install --upgrade pip
Style Guide
To make reading others guide easier this guide has use the PEP8 style guide. It provides guidelines for how many spaces to use on indents, how to name variables and classes, and a lot more. When sharing with others it is good to agree on a style to make your code legible and not waste time refactoring code between programmer styles.
Parts of a program
From IGTP
#!/usr/bin/env python3 # if file is executable as a script
module docstring imports metadata / globals/ logging implementation if name == ‘main’: # if file is executable as a script argparse
Testing your Code
Types of testing
Automated testing is the opposite of exploratory testing. Exploratory testing is using the program/exploring the program to find errors.
The simplest start of a test is to use an assert test
def test_sum():
assert sum([1, 2, 3]) == 6, "Should be 6"
def test_sum_tuple():
assert sum((1, 2, 2)) == 6, "Should be 6"
if __name__ == "__main__":
test_sum()
test_sum_tuple()
print("Everything passed")
To streamline running multiple tests, there are test runners. 3 popular test runners are unittest, nose2 and pytest.
nose2 adds features on top of unittest.
Unittest
To run a unit test python3 unittest_threats.py KingThreatsTestCase
This example runs a unit test on the kings_threats function
import unittest
import sys
from piece_threats import king_threats,trim_threatened
class KingThreatsTestCase(unittest.TestCase):
# Pass into test (N,i, current_column, threatened), board_size)
def test_king_2x2_1(self):
result = trim_threatened(king_threats(2,2,1,1,{1}), 4)
self.assertEqual(result, {1,2,3,4})
if __name__ == '__main__':
unittest.main()
Building Applications
Once the application is written it is time to build it so it can be distributed and run.
Appendix
Zen of Python
- Beautiful is better than ugly.
- Explicit is better than implicit.
- Simple is better than complex.
- Complex is better than complicated.
- Flat is better than nested.
- Sparse is better than dense.
- Readability counts.
- Special cases aren’t special enough to break the rules.
- Although practicality beats purity.
- Errors should never pass silently.
- Unless explicitly silenced.
- In the face of ambiguity, refuse the temptation to guess.
- There should be one– and preferably only one –obvious way to do it.
- Although that way may not be obvious at first unless you’re Dutch.
- Now is better than never.
- Although never is often better than right now.
- If the implementation is hard to explain, it’s a bad idea.
- If the implementation is easy to explain, it may be a good idea.
- Namespaces are one honking great idea – let’s do more of those! (PEP20)
Sources
- Harrison, Matt (2017); “Illustrated Guide to Python”
- python.org
- Python Morsels