Skip to content

@kracekumar /Writing better python code.md
Last active

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Talk I gave at June bangpypers meetup.

Writing better python code


Swapping variables

Bad code

>>>a = 23
>>>b = 12
>>>temp = a
>>>a = b
>>>b = temp
>>>print a, b
12, 23

Pythonic

!python
>>>a, b = 23, 12
>>>a, b = b, a
>>>print a, b
12, 23

Counting Condition

Bad code

!python

>>>super_users = get_all_superusers_for_organization(org_name)
>>>if len(super_users) > 0:
>>>    print(u"Super users are {}".format(super_users))
>>>else:
>>>    print(u"No super users")

Pythonic

!python

>>>super_users = get_all_superusers_for_organization(org_name)
>>>if super_users:
>>>    print(u"Super users are {}".format(super_users))
>>>else:
>>>    print(u"No super users")

Accessing index of list

Bad code

!python

>>>langs = ["Python", "go", "lua"]
>>>index = 0
>>>length = len(langs)
>>>while index < length:
>>>    print(index, langs[index])
>>>    index += 1

Pythonic

!python

>>>langs = ["Python", "go", "lua"]
>>>for index, value in enumerate(langs):
>>>    print(index, value)

Check for one condition

Bad code

!python

>>>if user.is_superadmin or user.is_siteadmin or user.is_staff:
>>>    # Grant Access to some page

Pythonic

!python
>>>if any([user.is_superadmin, user.is_siteadmin, user.is_staff]):
>>>    # Grant Access to some page

Check for all condition

Bad code

!python

>>>if user.is_superadmin and user.is_siteadmin and user.is_staff:
>>>    # Grant Access to admin page

Pythonic

!python
>>>if all([user.is_superadmin, user.is_siteadmin, user.is_staff]):
>>>    # Grant Access to admin page

Range check

Bad code

!python

>>>status_code = requests.post("someurl", params={"foo": "bar"}).status_code
>>>if status_code >= 200 and status_code <= 299:
>>>    print("HTTP call is success")

Pythonic

!python

>>>status_code = request.post("someurl", params={"foo": "bar"}).status_code
>>>if 200 <= status_code <= 299:
>>>    print("HTTP call is success")

Is operator

Bad code

!python
>>>250 + 6 is 256
True

>>>250 + 7 is 257
False

Pythonic code

!python
>>>250 + 6 == 256
True

>>>250 + 7 == 257
True

Copy a list

Bad code

!python

>>>langs = ["Python", "Go", "Lua"]
>>>new_langs = langs
>>>new_langs.append("Javascript")
>>>print(langs, new_langs)
(['Python', 'Go', 'Lua', 'Javascript'], ['Python', 'Go', 'Lua', 'Javascript'])

Pythonic

!python
>>>langs = ["Python", "Go", "Lua"]
>>>new_langs = langs[:]
>>>new_langs.append("Javascript")
>>>print(langs, new_langs)
(['Python', 'Go', 'Lua'], ['Python', 'Go', 'Lua', 'Javascript'])

List comprehension

Bad code

!python

>>>nos = [1, 4, 5, 6]
>>>evens = []
>>>for no in nos:
>>>    if no % 2 == 0:
>>>        evens.append(no)
>>>print(evens)
[4, 6]

Pythonic

!python

>>>nos = [1, 4, 5, 6]
>>>evens = [no for no in nos if no % 2 == 0]
>>>print(evens)
[4, 6]

Function defaults

Bad code

!python

>>>def foo():
>>>    return "foo"

>>>def bar(names=[]):
>>>    names.append(foo())
>>>    return names

>>>bar()
["foo"]
>>>bar()
["foo", "foo"]

Function defaults ...

Pythonic

!python

>>>def bar(names=None):
>>>   name = foo()
>>>   if not names:
>>>       return [name]
>>>   names.append(name)
>>>   return names

>>>bar()
['foo']
>>>bar()
['foo']

Get a element in a dictionary

Bad code

!python

>>>d = {'foo': 'bar'}
>>>if 'baz' in d:
>>>    temp = d['baz']
>>>else:
>>>    temp = ""

Pythonic

!python

>>>d = {'foo': 'bar'}
>>>temp = d.get('baz', "")

Frequency count

Bad code

!python

>>>words = ["a", "the", "foo", "bar", "foo"]
>>>frequency = {}
>>>for word in words:
>>>    if word in frequency:
>>>        frequency[word] += 1
>>>    else:
>>>        frequency[word] = 1
>>>print(frequency)
{'a': 1, 'the': 1, 'foo': 2, 'bar': 1}

Frequency count ...

Pythonic

!python

>>>from collections import Counter
>>>frequency = Counter(words)
>>>print(frequency)
Counter({'foo': 2, 'a': 1, 'the': 1, 'bar': 1})

Raising KeyError in dictionary

Bad code

!python

#Look before you leap
>>>d = {'foo': 'bar'}
>>>if 'baz' in d:
>>>    temp = d['baz']
>>>else:
>>>    raise KeyError("baz is missing")

Pythonic

!python

#Easier to Ask for Forgiveness than Permission
>>>try:
>>>    temp = d["baz"]
>>>except KeyError:
>>>    raise KeyError("baz is missing")

Context manager

Bad code

!python

>>>f = open('foo.txt')
>>>print(f.read())
>>>f.close()

Pythonic

!python

>>>with open('foo.txt') as f:
>>>    print(f.read())

Iterating over a file

Bad code

!python

>>>with open('foo.txt') as f:
>>>    for line in f.readlines():
>>>        print(line)

Pythonic

!python

>>>with open('foo.txt') as f:
>>>     for line in f:
>>>         print(line)

dot accessors

Bad code

!python

>>>class Person(object):
>>>    def __init__(self, name, email):
>>>        self.name = name
>>>        self.email = email
>>>p = Person("kracekumar", "me@kracekumar.com")
>>>print(p.name, p.email)
('kracekumar', 'me@kracekumar.com')

dot accessors ...

Pythonic

!python

>>>from collections import namedtuple
>>>Person = namedtuple('Person', ['name', 'email'])
>>>p = Person("kracekumar", "me@kracekumar.com")
>>>print(p.name, p.email)
('kracekumar', 'me@kracekumar.com')

Exceptions

Bad code

!python

>>>try:
>>>   foo()
>>>except:
>>>   print("something") # sometimes people write pass. PURE EVIL !

Pythonic

!python

>>>try:
>>>   foo()
>>>except (IndexError, KeyError) as e:
>>>    print("something went wrong")

Q & A


Thanks

@irvingprog

Great, even copy list example is not about of pythonic or not pythonic code If not about the same python, see objects and references.

@kracekumar
Owner

Agreed, I explained this in the talk!

@toyg

Raising an exception just to manipulate a dict looks bad to me: you're gratuitously invoking exception-handling machinery (which it will probably have performance implications) and perverting it into glorified if/else statements (something most original OOP proponents see as pointless, with good reason). You point out dict.get() above, that's much better imho.

The other suggestions are very good :+1: I use most of them except for any() / all().

@dvirsky

Nice bunch of tips. I often use a slightly more abbreviated version of file/line iteration:

>>>for line in open('foo.txt'):
>>>         print(line)

I'd also write something about generators maybe.

@Ivoz

If your things to check are already in an iterable, then all and and would be more pythonic. Arguing they're somehow more pythonic over normal or or ands is wrong, and can be less clear for such few conditions (why do I need to construct a list just for this?).

@kracekumar
Owner

@ivoz It depends when there are 5 to 6 different conditions to check. Agreed all/any is always preferred with generators.

@acutesoftware

Good tips, but why is the dot accessors example using a class bad? (Assume there is more in the class than just the example)

@joshkehn

Disagree with dot accessors, KeyError raising for dicts, any and all are preferences.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.