Idiomatic programming?

The Python Idioms

idiom

A group of words whose meaning cannot be predicted from the meanings of the constituent words, as for example (It was raining) cats and dogs.
Linguistic usage that is grammatical and natural to native speakers of a language.
The characteristic artistic style of an individual, school, period, etc

Etymology: 16th Century: from Latin idiōma, peculiarity of language.

Python?

A dynamically and strong typed, memory-managed and multiparadigm language created by Guido van Rossum in 1991.

Current version is 3.4.1

The Zen of Python

>>> import this
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...

Hello, world!

C++

#include <iostream>

int main()
{
    std::cout << "Hello, world!\n";
}

Java

public class HelloWorld {
   public static void main(String[] args) {
       System.out.println("Hello, world!");
   }
}

Python

print('Hello, world!')

Special syntax

List repetition

Don't write:

vector = []
for _ in range(10):
  vector.append(0)

Write:

vector = [0] * 10

Destructured assignment

Don't write:

point = (1, 2, 3)
x = point[0]
y = point[1]
z = point[2]

Write:

point = (1, 2, 3)
x, y, z = point

Multiple assignment

Don't write:

aux = b
b = a
a = aux

Write:

a, b = b, a

Interval test

Don't write:

if 0 < 1 and 1 < 2:
  print('something...')

Write:

if 0 < 1 < 2:
  print('something...')

Lambdas

Don't write:

def pow_4(v):
  return v ** 4
map(pow_4, (1, 2, 3))

Write:

map(lambda i: i ** 4, (1, 2, 3))

Truthy & Falsy

Don't write:

if len(l) != 0:
  print('Non-empty list')
if len(d) != 0:
  print('Non-empty dictionary')
if a != 0:
  print('Non-zero number')
if o != None:
  print('Non-null object')
if s != '':
  print('Non-empty string')

Write:

if l: print('Non-empty list')
if d: print('Non-empty dictionary')
if a: print('Non-zero number')
if o: print('Non-null object')
if s: print('Non-empty string')

not in

Don't write:

if not ('key' in d):
  print('key is not in the dictionary')

Write:

if 'key' not in d:
  print('key is not in the dictionary')

Negative indexing

Don't write:

last_item = collection[len(collection)-1]

Write:

last_item = collection[-1]

Loops

Ranging

Don't write:

i = 0
while i < 10:
  print(i)
  i += 1

Write:

for i in range(10):
  print(i)

Iterating

Don't write:

for i in range(len(collection)):
  item = collection[i]
  item.doSomething()

Write:

for item in collection:
  item.doSomething()

Enumerating

Don't write:

for i in range(len(collection)):
  item = collection[i]
  item.doSomething(i)

Write:

for i, item in enumerate(collection):
  item.doSomething(i)

Multidimensional ranging

Don't write:

for x in range(10):
  for y in range(5):
    for z in range(2):
      print(x, y, z)

Write:

from itertools import product
for x, y, z in product(range(10), range(5), range(2)):
  print(x, y, z)

Reversed iterations

Don't write:

i = len(collection) - 1
while i >= 0:
  item = collection[i]
  item.doSomething()
  i -= 1

Write:

for item in reversed(collection):
  item.doSomething()

Dictionaries

Dictionary comprehensions

Don't write:

keys = ('a', 'b', 'c')
values = (1, 2, 3)
d = {}
for i, k in enumerate(keys):
  d[k] = values[i]

Write:

keys = ('a', 'b', 'c')
values = (1, 2, 3)
d = { k:v for k, v in zip(keys, values) }

Sets

Don't write:

first_ten = { k:k for k in range(10) }

Write:

first_ten = { k for k in range(10) }

Default dictionaries

Don't write:

words = "as much as possible".split()
d = {}
for w in words:
  if w not in d:
    d[w] = 0
  d[w] += 1

Write:

from collections import defaultdict
words = "as much as possible".split()
d = defaultdict(lambda: 0)
for w in words:
  d[w] += 1

Iterating through dictionaries

Don't write:

for k in d:
  v = d[k]
  print('Content of d for key ' + k + ' is ' + v)

Write:

for k, v in d.items():
  print('Content of d for key ' + k + ' is ' + v)

Default get()

Don't write:

if 'key' not in d:
  result = 'default value'
else:
  result = d['key']

Write:

result = d.get('key', 'default value')

Lists & tuples

Lists comprehensions

Don't write:

odds = []
for v in range(100):
  if v % 2:
    odds.append(v)

Write:

odds = [v for v in range(100) if v % 2]

Tuple comprehensions

(generators)

Don't write:

odds = []
for v in range(100):
  if v % 2:
    odds.append(v)
t = tuple(odds)

Write:

odds = (v for v in range(100) if v % 2)

Named tuples

Don't write:

class Point(object):
  def __init__(self, x, y):
    self._tuple = (x, y)
    self.x = x
    self.y = y

  def __getitem__(self, i):
    return self._tuple[i]

p = Point(1, 2)
p[0] == p.x

Write:

from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
p[0] = p.x

Avoid parenthesis

Don't write:

sum( (d for d in range(1000)) )

Write:

sum(d for d in range(1000))

Slices

Don't write:

l = [1, 2, 2, 3]
sublist = []
for i in range(1, 3):
 sublist.append(l[i])

Write:

l = [1, 2, 2, 3]
sublist = l[1:3]

in a list

Don't write:

if v == 'a' or v == 'b' or v == 'c':
  print('do something')

Write:

if v in ('a', 'b', 'c'):
  print('do something')

Strings

Concatenation

Don't write:

colors = ['red', 'blue', 'yellow', 'black']
result = ''
for i, color in enumerate(colors):
  result += color
  if i < len(color) - 2:
    result += ', '

Write:

result = ', '.join(['red', 'blue', 'yellow', 'black'])

Formatting

Don't write:

x = 1
y = 2
print('P(' + str(x) + ', ' + str(y) + ')')

Write:

x = 1
y = 2
print('P({x}, {y})'.format(x=x,y=y))

in operator

Don't write:

s = 'once upon a time'
contained = false
for c in s:
  if c == 'p':
    contained = True
    break

Write:

s = 'once upon a time'
contained = 'p' in s

Docstrings

Don't write:

class Quaternion(object):
  pass

Write:

class Quaternion(object):
  """Implements quaternion-related operations."""

Contexts

Setup & Teardown

Don't write:

# setup code
try:
  # usefull code
finally:
  # teardown code

Write:

class MyContext(object):
  def __enter__(self):
    """Here is the startup code"""
  def __exit__(selft, *args):
    """Here is the teardown code"""
with MyContext():
  # usefull code

Files

Don't write:

try:
  f = open(path)
  # do something
finally:
  f.close()

Write:

with open(path) as f:
  # do something

Only files?

Don't write:

try:
  page = urlopen(url)
  # do something
finally:
  page.close()

Write:

from contextlib import closing
with closing(urlopen(url)) as page:
  # do something

Ignoring exceptions

Don't write:

import os
try:
  os.remove(some_path)
except FileNotFoundError:
  pass

Write:

from contextlib import suppress
with suppress(FileNotFoundError) :
  os.remove(some_path)

Where to find idioms?

But remember the Zen of Python

practicality beats purity

About me

me
Salvador de la Puente González
twitter
@salvadelapuente
My web sites
http://unoyunodiez.com
http://github.com/delapuente