In [1]:
import logging
import functools
import itertools

import numpy as np
logging.root.setLevel(logging.DEBUG)

Idiomatic


In [2]:
import this


The Zen of Python, by Tim Peters

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!

ugly


In [3]:
title = "title"
print("<html>")
print("<head>")
print("<title>" + title + "</title>")
print("</head>")
print("<body>")
print("<h1>" + title + "</h1>")
print("</body>")
print("</html>")


<html>
<head>
<title>title</title>
</head>
<body>
<h1>title</h1>
</body>
</html>

In [4]:
template = """<html>
 <head>
  <title>{title:s}</title>
 </head>
 <body>
 <h1>{title:s}</h1>
 </body>
</html>
"""
print(template.format(title=title))


<html>
 <head>
  <title>title</title>
 </head>
 <body>
 <h1>title</h1>
 </body>
</html>


In [5]:
a = [2,3,5]
sum_of_squares = 0
for i in range(len(a)):
    sum_of_squares = sum_of_squares + a[i] * a[i]
sum_of_squares


Out[5]:
38

In [6]:
sum(x**2 for x in a)


Out[6]:
38

In [11]:
(letter for letter in 'word')


Out[11]:
<generator object <genexpr> at 0x7fcd84087a50>

In [7]:
arr = np.array(a)
(arr**2).sum()


Out[7]:
38

In [13]:
colors = ["red", "yellow", "blue", "purple"]

In [14]:
for i in range(len(colors)):
    print(colors[i])


red
yellow
blue
purple

In [15]:
for color in colors:
    print(color)


red
yellow
blue
purple

In [18]:
sorted_colors = colors[:]
sorted_colors.sort()
for color in sorted_colors:
    print(color)


blue
purple
red
yellow

In [12]:
for color in sorted(colors):
    print(color)


blue
purple
red
yellow

In [13]:
for i in range(len(colors)):
    print("{}: {}".format(i, colors[i]))


0: blue
1: purple
2: red
3: yellow

In [14]:
for i, color in enumerate(colors):
    print("{}: {}".format(i, color))


0: blue
1: purple
2: red
3: yellow

In [15]:
variables = ["height", "length", "width", "volume"]
for i in range(len(variables)):
    variable = variables[i]
    color = colors[i]
    print("{i}: {color}, {variable}".format(i=i, color=color, variable=variable))


0: blue, height
1: purple, length
2: red, width
3: yellow, volume

In [19]:
zip([1,2,3], ['a', 'b', 'c'])


Out[19]:
[(1, 'a'), (2, 'b'), (3, 'c')]

In [16]:
variables = ["height", "length", "width", "volume"]
for i, (variable, color) in enumerate(zip(variables, colors)):
    print("{i}: {color}, {variable}".format(i=i, color=color, variable=variable))


0: blue, height
1: purple, length
2: red, width
3: yellow, volume

In [17]:
letters = ["C","a", "b"]
list(sorted(letters))


Out[17]:
['C', 'a', 'b']

In [18]:
def case_independent_cmp(a, b):
    return cmp(a.lower(), b.lower())
list(sorted(letters, cmp=case_independent_cmp))


Out[18]:
['a', 'b', 'C']

In [19]:
list(sorted(letters, key=str.lower))


Out[19]:
['a', 'b', 'C']

Explicit is better than implicit


In [22]:
from math import *
from numpy import *
import logging

log([1,2,3, 2])


Out[22]:
array([ 0.        ,  0.69314718,  1.09861229,  0.69314718])

In [23]:
from numpy import *
from math import *
try:
    log([1,2,3, 2])
except:
    logging.exception("that does not compute")


ERROR:root:that does not compute
Traceback (most recent call last):
  File "<ipython-input-23-f2e5e3862da6>", line 4, in <module>
    log([1,2,3, 2])
TypeError: a float is required

In [22]:
import numpy as np
np.log([1,2,3, 2])


Out[22]:
array([ 0.        ,  0.69314718,  1.09861229,  0.69314718])

In [24]:
"it's %d o'clock" % (3,)


Out[24]:
"it's 3 o'clock"

In [23]:
try:
    "It is " +3 + " o'clock"
except:
    logging.exception("Strong typing please!")


ERROR:root:Strong typing please!
Traceback (most recent call last):
  File "<ipython-input-23-64cdd9f2df20>", line 2, in <module>
    "It is " + 3 + " o'clock"
TypeError: cannot concatenate 'str' and 'int' objects

In [24]:
"It is {hours:d} o'clock".format(hours=3)


Out[24]:
"It is 3 o'clock"

Simple/Complex/Complicated


In [25]:
DEBUG = True
def calculate():
    if DEBUG:
        print("starting calculate")
    1 + 1
    if DEBUG:
        print("finished calculate")
calculate()


starting calculate
finished calculate

In [26]:
def log_call(func):
    logging.debug("starting {}")
    func()
    logging.debug("finished {}")
    
@log_call
def calculate():
    1 + 1


DEBUG:root:starting {}
DEBUG:root:finished {}

Flat is better than nested


In [27]:
# in java:
# import org.apache.xerces.impl.xpath.regex.EXIRegularExpression;
import re

In [28]:
import requests
import xml.etree.ElementTree

url = 'http://live.waterbase.nl/metis/cgi-bin/mivd.pl?action=value&code=DOOVBWT&format=xml&lang=nl&order=code&type=loc'
doc = xml.etree.ElementTree.fromstring(requests.get(url).content)
doc.getchildren()[0].\
    getchildren()[0].\
    getchildren()[0].\
    getchildren()[2].\
    getchildren()[0].\
    getchildren()[0].\
    getchildren()[0].\
    getchildren()[0].\
    text


INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): live.waterbase.nl
DEBUG:requests.packages.urllib3.connectionpool:"GET /metis/cgi-bin/mivd.pl?action=value&code=DOOVBWT&format=xml&lang=nl&order=code&type=loc HTTP/1.1" 200 None
Out[28]:
'131200,562950'

In [29]:
doc.find('.//gml:Coordinates', namespaces={'gml': 'http://www.opengis.net/gml'}).text


Out[29]:
'131200,562950'

Errors should never pass silent


In [30]:
try:
    pay_salary(amount)
except:
    pass

Unless explicitly silenced


In [25]:
def transfer(amount, account):
    if not isinstance(amount, int):
        raise TypeError("expected integer, got %s" % (type(amount), ))
    print("paying %d to %s" % (amount, account))
    
extra = 0
amount = 23.43
for i in range(5):
    try:
        # try if we can transfer
        transfer(amount, "bank")
    except TypeError:
        # amount is a floating point
        transfer(int(amount), "bank")
        extra += amount - int(amount)
        if extra > 1:
            transfer(int(extra), "fedor")
            extra -= int(extra)


paying 23 to bank
paying 23 to bank
paying 23 to bank
paying 1 to fedor
paying 23 to bank
paying 23 to bank
paying 1 to fedor

In [ ]: