Set up
Virtual environments
Create a new one with:
python virtualenv/virtualenv.py venv_name
Control it with:
source venv_name/bin/activate
source venv_name/bin/deactivate
There is a new way to do this with the venv module in Python 3.
python -m venv venv_name
source venv_name/bin/activate
Package management
Use pip (aka the cheese shop).
pip install --upgrade flask
pip freeze >requirements.txt
pip install -r requirements.txt
pip list --outdated
pip uninstall flask
Basics
Basics
Example:
brush:python
import re
import sys
def replace(s):
return re.replace(s,"a","b")
if __name__ = "main":
print(replace(__name__)
sys.exit(0)
Main defines
brush:python
print(__name__) # Name of module
print(__file__) # Location of this file
Text
brush:python
a = "hello".title() # Title case
b = "WoRlD".lower() # To lower
Classes
A class has the form:
brush:python
Class Dog:
def __init__(self, name):
self.name = name
def __repr__(self):
return "dog({})".format(self.name)
# Optional, otherwise __repr__ is called
def __str__(self):
return "I am a dog. My name is {}".format(self.name)
You can define member functions and variables.
You can inherit from other classes:
brush:python
Class Akita(Dog):
def __init__(self):
self.name = "Akita"
List comprehensions
Creates a new list based on a certain condition:
brush:python
data = [1,2,3,4,5,6]
print [x for x in data]
print [x for x in data if x >3]
print [x*x for x in data]
Loops
brush:python
for I in aList:
print(I)
Use xrange (iterator) instead of range (generator):
brush:python
for n in xrange(1,10000):
print(n)
You can make your own iterators.
Advanced
Exceptions
Define an exception class:
brush:python
class MyException(Exception):
def __init__(self, msg):
self.msg = msg
And call it from the code:
brush:python
def liveDangerously():
raise MyException("It's dead, Jim")
Detect the exception from the code and act accordingly:
brush:python
try:
liveDangerously()
except MyException as exc:
print(exc.msg)
Lambda functions
The following example sort list alist by the foo attribute of each alist instance:
brush:python
alist.sort(key=lambda x: x.foo)
Assigning a function to a variable:
brush:python
f = lambda x, y : x + y
f(1,2)
The map function:
brush:python
Celsius = [39.2, 36.5, 37.3, 37.8]
Fahrenheit = map(lambda x: (float(9)/5)*x + 32, Celsius)
With several lists:
brush:python
a = [1,2,3,4]
b = [17,12,11,10]
map(lambda x,y:x+y, a,b)
Reduce:
brush:python
reduce(lambda x,y: x+y, [47,11,42,13])
f = lambda a,b: a if (a > b) else b
reduce(f, [47,11,42,102,13])
References:
Run-time introspection
brush:python
instance.attribute_name
# Or
getattr(instance, attribute_name)
Override for those undefined attributes only. Catches accesses to undefined attributes:
brush:python
class Foo(object):
def __init__(self, a):
self.a = 1
def __getattr__(self, attr):
return "Help!"
This one catches all accesses to attributes. Overriding getattribute can lead to infinite recursion.
brush:python
class Foo(object):
def __init__(self, a):
self.a = 1
def __getattribute__(self, attr):
return super(Foo, self).__getattribute__(attr)
Set attribute
brush:python
__setattribute__
Text formatting
Text formatting
Old style:
brush:python
print("Hello: %s"%("Bob"))
New style:
brush:python
print("Hello: {}".format("Bob"))
Look here for a complete comparison.
Best practices
Module structure
A Python modules has the following components:
README.rst
LICENSE
setup.py
requirements.txt
sample/__init__.py
sample/core.py
sample/helpers.py
docs/conf.py
docs/index.rst
tests/test_basic.py
tests/test_advanced.py
Example Makefile
init:
pip install -r requirements.txt
test:
py.test tests
.PHONY: init test
Links:
Documenting the code
brush:python
def square_and_rooter(x):
"""Return the square root of self times self."""
...
Use Sphynx to process documentation.
Logging
The Logging module simplifies log creation.
Each module should start with the following boilerplate code:
brush:python
import logging
# Optional configuration
logging.basicConfig(
level = logging.DEBUG,
filename = "my.log",
filemode='w',
format='%(asctime)s:%(levelname)s:%(message)s')
log = logging.getLogger(__name__)
# log.setFormatter()
log.setLevel(logging.DEBUG)
Other loggers can be customised in main program, after they are loaded:
brush:python
logging.getLogger("noisyModule").setLevel(logging.CRITICAL)
Log messages can be created with different levels:
brush:python
log.debug("Preparing bases")
log.info("Print number %d", 3)
log.warning("I don't like this number")
log.error("The number is not right")
log.critical("System failure!")
log.log(10, "Custom log level")
Also from an exception:
brush:python
try:
# raise exception
except Exception as e:
log.exception("Exception %s", e)
Log levels can be one of:
- 10: logging.DEBUG
- 20: logging.INFO
- 30: logging.WARNING
- 40: logging.ERROR
- 50: logging.CRITICAL
Messages can contain any of:
- %s
- %d
- %f
- %i
We can also forward logs to a file:
brush:python
filelog = logging.FileHandler(filename)
filelog.setFormatter(logging.formatter("$(asctime)s [%(threadname)16s][%(module)14s][%(levelname)8s] %(message)s"))
logging.getLogger('').addHandler(filelog)
Testing
Testing with doctest
The doctest module allows a module to contains its own tests in the form of commands run in an interactive shell:
brush:python
Class Dog():
'''
>>> r= Dog("Yeti")
>>> r.name
'Yeti'
'''
def __init__(self, name):
self.name = name
The following boilerplate code runs the tests when the module is called directly:
brush:python
if __name__ == "__main__":
import doctest
doctest.testmod()
Testing with unittest
brush:python
import unittest
class DogTest(unittest.TestCase):
def setUp(self):
return
def tearDown(self):
return
def testCalculation(self):
self.assertEqual(fib(0), 0)
self.assertEqual(fib(1), 1)
self.assertEqual(fib(5), 5)
self.assertEqual(fib(10), 55)
self.assertEqual(fib(20), 6765)
if __name__ == "__main__":
unittest.main()
Test are run from the command line:
cd project_directory
python -m unittest discover
Argument parsing
First we create an argument parser:
brush:python
from argparse import ArgumentParser
arg_parser = ArgumentParser(description='My program description')
arg_parser.add_argument('name', metavar='name',
help='name of the file')
arg_parser.add_argument('-v', "--verbose", action='store_true', dest='index',
help='verbose')
Arguments can be:
- positional vs. -option ("name" vs. "-v" above)
Argument properties:
- required
- type=int
- action="store_true"
- action="count"
- choices = [0, 1, 2]
- default = 0
Then we parse the arguments
brush:python
args = arg_parser.parse_args()
And then we can access the arguments via the parser object as properties:
brush:python
# Access arguments with args
if args.index:
print("Verbose mode enabled")
Parsing
brush:python
import pyparsing as pp
We create rules for typical syntact tokens
brush:python
# Basic tokenizer
COMMA = pp.Literal(",").suppress()
LB = pp.Literal("{").suppress()
RB = pp.Literal("}").suppress()
And also for more complex tokens:
brush:python
INTEGER = pp.Word()
IDENT = pp.Word()
Finally, we create the grammar:
brush:python
op = INTEGER | IDENT
And we parse the input:
brush:python
r = parser.parseFile(filename, parseAll = True)
print r
PyParsing pattern
An example can be found here. I prefer to separate the parsing from the class, to keep separation of concerns:
brush:python
import pyparsing as pp
class Number(oject):
def __init__(self, num):
self.value = num
def __repr__(self):
return str(self.value)
class Expression:
def __init__(self, left, op, right):
self.left = left
self.op = op
self.right = right
def __repr__(self):
return "({} {} {})".format(self.left, self.op, self.right)
class ExpressionParser:
def __init__(self):
self.parser = self.grammar()
def grammar(self):
num = INTEGER.setParseResults(self.parseNum)
expr = pp.Group(INTEGER + PLUS + INTEGER).setParseResults(self.parseExpr)
def parseNum(self, tokens):
return Number(int(tokens[0]))
def parseExpr(self, tokens):
(l, op, r) = tokens[0]
return Expression(l, op, r)
Parsing errors can be reported:
brush:python
try:
parser.parseString(t)
except ParseException as pe:
print(pp.line(pe.loc, t))
print(' '*(pp.col(pe.loc,t) + '^')
We can also dump the data:
brush:python
d = parser.parseString(t)
print(d.dump())
NumPy
Some examples
brush:python
import numpy as np
a = np.array([2,3,4])