Be more pythonic

Pyladies Berlin, 2015

by Mei Li Triantafyllidi

Zen of python

PEP8

No tabs

4 spaces indentation

Yes: spam(ham[1], {eggs: 2})
No:  spam( ham[ 1 ], { eggs: 2 } )

Whitespaces

Yes: x, y = y, x
No:  x , y = y , x
Yes: counter = counter + 1
No:  counter=counter+1
Yes: result = add(x+1, 3)
Yes: result = add(x + 1, 3)
Yes: import os
     import sys

No:  import sys, os

 

No: from subprocess import *
Yes: from subprocess import Popen, PIPE

Import statements

Naming conventions

  • lower_case_under for variables and functions and methods
  • WordCap for classes
  • ALL_CAPS for constants

Tools

  • pep8
  • pylint
  • pyflakes

 

most IDEs have a plugin

Pythonic code patterns

Swap variables

No:

tmp = b
b = a
a = tmp

 

Yes:

a, b = b, a

Swap variables more


tmp_x = x + dx * t
tmp_y = y + dy * t
tmp_dx = influence(m, x, y, dx, dy, partial='x')
tmp_dy = influence(m, x, y, dx, dy, partial='y')
x = tmp_x
y = tmp_y
dx = tmp_dx
dy = tmp_dy

No

Yes


x, y, dx, dy = (x + dx * t,
                y + dy * t,
                influence(m, x, y, dx, dy, partial='x'),
                influence(m, x, y, dx, dy, partial='y'))

Unpacking tuples

person_info = ("Mary", 27)

## Don't do
name = person_info[0]
age = person_info[1]


## Do
name, age = person_info

Iteration

## Don't do
for i in [0, 1, 2, 3, 4]:
    print i

## Don't do
for i in range(5):
    print i

## Do
for i in xrange(5):
    print i

## Python 3 - only range

Iteration over list

colors = ['red', 'green', 'blue', 'yellow']

# Don't do
for i in range(len(colors)):
    print colors[i]

# Do
for color in colors:
    print color

Iteration over list with index

colors = ['red', 'green', 'blue', 'yellow']

## Don't do
for i in range(len(colors)):
    print i, '-->', colors[i]

## Do
for i, color in enumerate(colors):
    print i, '-->', color

List comprehension


## Don't do
names = []
for kid in kids:
    names.append(kid["name"])

## Do
names = [kid["name"] for kid in kids]


## Don't do
baby_names = []
for kid in kids:
    if kid["age"] < 1:
        baby_names.append(kid["name"])

## Do
names = [kid["name"] for kid in kids if kid["age"] > 1]

Use builtins - sum


## Get sum of all numbers until 100
## Don't do
total = 0
for num in range(101):
    total += num

## Do
total = sum(range(101))

## Get sum of all squares of numbers until 100
## Don't do
total = 0
for num in range(101):
    total += num**2

## Do
total = sum([n**2 for n in range(101)])

Generators


## Don't do 
total = sum([n**2 for n in range(101)])

## Do
total = sum(n**2 for n in range(101))

Concatenate list strings

## Don't do
s = names[0]
for name in names[1:]:
    s += ', ' + name

## Do
s = ', '.join(names)

Sort list

names = ["Mary", "John", "Peter", "Helen"]


for name in sorted(names):
    print name

## sort by string length
for name in sorted(names, key=len):
    print name

## Sorting descending
for name in sorted(names, reverse=True):
    print name

Counting with dictionaries

colors = ['red', 'green', 'red', 'blue', 'green', 'red']

# Don't do
d = {}
for color in colors:
    if color not in d:
        d[color] = 0
    d[color] += 1

# {'blue': 1, 'green': 2, 'red': 3}

# Do
d = {}
for color in colors:
    d[color] = d.get(color, 0) + 1

Grouping with dictionaries

colors = ['gray', 'black', 'yellow', 'blue', 'green', 'red']

# Don't do
d = {}
for color in colors:
    first_char = color[0]
    if first_char not in d:
        d[first_char] = []
    d[first_char].append(color)

# {'r': ['red'], 'b': ['black', 'blue'], 
#  'g': ['gray', 'green']}

# Do
d = defaultdict(list)
for color in colors:
    first_char = color[0]
    d[first_char].append(color)

Looping over dictionaries

city_music = {"berlin": "techno", 
              "seville": "flamenco", 
              "new york": "jazz"}

# only keys
for city in city_music:
    print city

# to change the dictionary while looping - Do
for city in city_music.keys():
    if city not in europe:
        del city_music[city]

Looping over dictionaries more

city_music = {"berlin": "techno", 
              "seville": "flamenco", 
              "new york": "jazz"}

for city in city_music:
    print city, 'listens to', city_music[city] 

# more readable
for city, music in city_music.items():
    print city, 'listens to', music 

# more readable and faster
for city, music in city_music.iteritems():
    print city, 'listens to', music

Reading files

# Do not do 
fp = open("notes.txt")
text = fp.read()
fp.close()

# Do 
with open("notes.txt") as fp:
    text = fp.read()

# read file line by line
with open("notes.txt") as fp:
    for line in fp:
        print line

what's next

  • decorators
  • property instead of getter, setter
  • staticmethod, classmethod

resources

Sum up

  • Beautiful is better than ugly
  • Readability counts
  • PEP8
  • read builtins, str methods, collections

... so read read read code

Let's practice 

http://exercism.io/

 

Be more pythonic

By Mei Li Triantafyllidi