Beautiful Python

Alicia Pérez

www.stylesage.co

Accent?

We are flying!

>>> import antigravity

Strings

colors = ['red', 'blue', 'green', 'yellow']
result = ''
for s in colors:
    result += s
# result: 'redbluegreenyellow'
colors = ['red', 'blue', 'green', 'yellow']
result = ''.join(colors)
# result: 'redbluegreenyellow'

Good

Bad

Create a string from a list

Strings

colors = ['red', 'blue', 'green', 'yellow']
result = ''
for s in colors:
    result += s + ','

result = result[:-1]
# result: 'red,blue,green,yellow'
colors = ['red', 'blue', 'green', 'yellow']
result = ','.join(colors)
# result: 'red,blue,green,yellow'

Good

Bad

Create a string from a list joined by comma

Strings

my_very_big_string = """For a long time I used to go to bed early. Sometimes,
    when I had put out my candle, my eyes would close so quickly that I had not even
    time to say "Im going to sleep."""
my_very_big_string = (
    "For a long time I used to go to bed early. Sometimes, "
    "when I had put out my candle, my eyes would close so quickly "
    "that I had not even time to say: Im going to sleep."
)

Good

Bad

Multi-line

Strings

contains?

stylesage = 'Fashion meets Big Data'
if stylesage.contains('Fashion'):
    pass

Bad

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'contains'

Strings

stylesage = 'Fashion meets Big Data'
if stylesage.find("Fashion") != -1:
    pass

Good

Bad

stylesage = 'Fashion meets Big Data'
if 'Fashion' in stylesage:
    pass

contains in

Strings

format

                               # OR
'%s %s' % ('one', 'two')              '%d %d' % (1, 2)
# output: 'one two'                   # output: '1 2'

New

Old

                               # OR
'{} {}'.format('one', 'two')          '{} {}'.format(1, 2)
# output: 'one two'                   # output: '1 2'

Strings

Basic format

                               # OR
'%s %s' % ('one', 'two')              '%d %d' % (1, 2)
# output: one two                     # output: 1 2

New

Old

                               # OR
'{} {}'.format('one', 'two')          '{} {}'.format(1, 2)
# output: one two                     # output: one two

# explicit positional index
'{1} {0}'.format('one', 'two')
# output: two one

Strings

Padding and aligning

                               # OR
'%10s' % ('test',)                    '%-10s' % ('test',)
# output: '      test'                # output: 'test      '

New

Old

                               # OR
'{:>10}'.format('test')               '{:10}'.format('test')
# output: '      test'                # output: 'test      '

Strings

Padding and aligning

                               # OR
'%10s' % ('test',)                    '%-10s' % ('test',)
# output: '      test'                # output: 'test      '

New

Old

                               # OR
'{:>10}'.format('test')               '{:10}'.format('test')
# output: '      test'                # output: 'test      '

# choose the padding character
'{:_<10}'.format('test')
# output: 'test______'

Strings

Padding and aligning

                               # OR
'%10s' % ('test',)                    '%-10s' % ('test',)
# output: '      test'                # output: 'test      '

New

Old

                               # OR
'{:>10}'.format('test')               '{:10}'.format('test')
# output: '      test'                # output: 'test      '

# choose the padding character
'{:_<10}'.format('test')
# output: 'test______'

# center align value
'{:_^10}'.format('test')
# output: '___test___'

Strings

Padding and aligning

New

# This operations are not available with old-style formatting

'{:=5d}'.format((- 23))
# output: '-  23'

'{:%Y-%m-%d %H:%M}'.format(datetime(2001, 2, 3, 4, 5))
# output: '2001-02-03 04:05'

person = {'first': 'Jean-Luc', 'last': 'Picard'}
'{p[first]} {p[last]}'.format(p=person)
# output: 'Jean-Luc Picard'

data = [4, 8, 15, 16, 23, 42]
'{d[4]} {d[5]}'.format(d=data)
# output: '23 42'

tu = (12,45,22222,103,6)
print '{0} {2} {1} {2} {3} {2} {4} {2}'.format(*tu)
# output: '12 22222 45 22222 103 22222 6 22222'

Booleans

if len(items) != 0:
    pass

if name != "":
    pass

Good

Bad

if items:
    pass

if name:
    pass

Check if variable equals a constant

False True
​False (== 0) True (== 1)
"" (empty string) any string but "" (" ", "anything")
0, 0.0 any number but 0 (1, 0.1, -1, 3.14)
[], (), {}, set() any non-empty container ([0], (None,),[''])
None almost any object that's not explicitly False

Booleans

Check if variable equals a constant

Booleans

if x >= start and x <= end:
    # do stuff

Good

Bad

if start <= x <= end:
    # do stuff

Chained comparisons

Comparisons

values = range(10)
i = 0
found = False
while not found and i < len(values):
    found = not values[i] % 2
    i += 1

Good

Bad

values = range(10)
anyPair = any([not value % 2 for value in values])

# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# [True, False, True, False, True, False, True, False, True, False]
# anyPair: True

Any

Comparisons

values = range(10)
i = 0
allPairs = True
while allPairs and i < len(values):
    allPairs = not values[i] % 2
    i += 1

Good

Bad

values = range(10)
allPairs = all([not value % 2 for value in values])

# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# [True, False, True, False, True, False, True, False, True, False]
# output: True

All

Comparisons

if x > 10:
    result = 'Yes'
else:
    result = 'No'

Good

Bad

result = 'Yes' if x > 10 else 'No'

Ternary operator

Lists

mylist = ['yellow', 'red', 'blue', 'green', 'black']

mylist[1:4]
# output: ['red', 'blue', 'green']

mylist[2:]
# output: ['blue', 'green', 'black']

mylist[:2]
# output: ['yellow', 'red']

mylist[-1]
# output: 'black'

mylist[1:-1]
# output: ['red', 'blue', 'green']

Manipulation

Lists

a = [3, 4, 5]
for i in range(len(a)):
    a[i] += 3

Good

Bad

a = [3, 4, 5]
a = [i + 3 for i in a]
# Or:
a = map(lambda i: i + 3, a)

List comprehensions

Lists

a = [3, 4, 5]
b = []
for i in a:
    if i > 4:
        b.append(i)

Good

Bad

a = [3, 4, 5]
b = [i for i in a if i > 4]
# Or:
b = filter(lambda x: x > 4, a)

Filter

Lists

a = [3, 4, 5]
i = 0
for item in items:
    print i, item
    i += 1

Good

Bad

a = [3, 4, 5]
for i, item in enumerate(a):
    print i, item

Enumerate

Generators

def firstn(n):
    num, nums = 0, []
    while num < n:
        nums.append(num)
        num += 1
    return nums

sum_of_first_n = sum(firstn(1000000))

Bad

def firstn(n):
    num = 0
    while num < n:
        yield num
        num += 1

sum_of_first_n = sum(firstn(1000000))

Good

Not in memory list

Generators

square = [i*i for i in xrange(1000000)]

List

square = (i*i for i in irange(1000000))

Generator

Generator vs list

Tuples

temp = a
a = b
b = temp
b, a = a, b

Good

Bad

Swap values

Tuples

l =['David', 'Pythonista', '+1-514-555-1234']
name, title, phone = l
# name: 'David'
# title: 'Pythonista'
# phone: '+1-514-555-1234'

Unpacking

Tuples

List of tuples

names = ['John', 'Eric', 'Terry']
surnames = ['Cleese', 'Idle', 'Gilliam']
people = []
for i in range(len(names)):
    people.append((names[i], surnames[i]))
print(people)
# output: [('John', 'Cleese'), ('Eric', 'Idle'), ('Terry', 'Gilliam')]
names = ['John', 'Eric', 'Terry']
surnames = ['Cleese', 'Idle', 'Gilliam']
zip(names, surnames)
# output: [('John', 'Cleese'), ('Eric', 'Idle'), ('Terry', 'Gilliam')]

Good

Bad

Dictionaries

Good

Bad

if d.has_key(key):
    print(d[key])
if key in d:
    print(d[key])

Dictionaries

Good

Bad

for key in d.keys():
    print key
for key in d:
    print key

Except

for key in d.keys():
    d[str(key)] = d[key]

Dictionaries

navs = {}
for (portfolio, equity, position) in data:
    if portfolio not in navs:
        navs[portfolio] = 0
    navs[portfolio] += position * prices[equity]

Good

Bad

for (portfolio, equity, position) in data:
    navs[portfolio] = (navs.get(portfolio, 0)
                       + position * prices[equity])
navs = {}
for (portfolio, equity, position) in data:
    if portfolio not in navs:
        navs[portfolio] = 0
    navs[portfolio] += position * prices[equity]
for (portfolio, equity, position) in data:
    navs.setdefault(portfolio, 0)
    navs[portfolio] += position * prices[equity]

Dictionaries

Good

Bad

navs = {}
for (portfolio, equity, position) in data:
    if portfolio not in navs:
        navs[portfolio] = 0
    navs[portfolio] += position * prices[equity]
navs = defaultdict(int)
for (portfolio, equity, position) in data:
    navs[portfolio] += position * prices[equity]

Dictionaries

Good

Bad

given = ['John', 'Eric', 'Terry', 'Michael']
family = ['Cleese', 'Idle', 'Gilliam', 'Palin']
pythons = {}
for i in range(len(given)):
    pythons[given[i]] = family[i]
given = ['John', 'Eric', 'Terry', 'Michael']
family = ['Cleese', 'Idle', 'Gilliam', 'Palin']
pythons = dict(zip(given, family))

Dictionaries

Good

Bad

values = range(4)
res = {}
for numb in values:
    res[numb] = chr(65 + numb)
res = {i : chr(65+i) for i in range(4)}

Dictionaries

Good

Bad

{0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}

What!?!?!

Interactive "_"

>>> 1 + 1
2
>>> _
2
>>> import math
>>> math.pi / 3
1.0471975511965976
>>> angle = _
>>> math.cos(angle)
0.50000000000000011
>>> _
0.50000000000000011
filename = 'foobar.txt'
basename, _, ext = filename.rpartition('.')

Variable "_"

from __future__

 

>>> from __future__ import braces
  File "<stdin>", line 1
SyntaxError: not a chance
from __future__ import division
print 8/7  # prints 1.1428571428571428
print 8//7 # prints 1

Beautiful Python

By aliciapj

Beautiful Python

  • 1,394