Skip to content

Instantly share code, notes, and snippets.

@kracekumar
Last active February 19, 2024 03:06
Show Gist options
  • Save kracekumar/09a60ec75a4de19b346e to your computer and use it in GitHub Desktop.
Save kracekumar/09a60ec75a4de19b346e to your computer and use it in GitHub Desktop.
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

@toyg
Copy link

toyg commented Jun 23, 2014

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 👍 I use most of them except for any() / all().

@dvirsky
Copy link

dvirsky commented Jun 23, 2014

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
Copy link

Ivoz commented Jun 23, 2014

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
Copy link
Author

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

@acutesoftware
Copy link

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
Copy link

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