Transforming Code into Beautiful, Idiomatic Python

Date:2013-03-15
Speaker:Raymond Hettinger
Slides:tbd

The Gist

  • “Don’t do this, do this instead.”
  • “Everywhere you see this, replace it with this.”
  • Replace all examples in these slides in your real code. Do it.

Replace things..

  • Replace index manip with core looping idioms
  • Use for..else and two arg form of iter()

Looping

  • Use xrange vs. range; Python 3: range IS xrange
  • Use enumerate() instead of range(len(iterable)) for indices
  • To loop backwards use reversed(iterable)
  • Use zip to loop over 2 collections
    • Use itertools.izip for large collections (or just default to it)
  • Use sorted(iterable) to loop in order
  • To loop until sential match, use iter(iterable, sentinel)
  • Track multiple exit points, use for..else vs. match + break

Dictionary skills

  • Fundamental Python skill

  • Linking, counting, grouping

  • Construct a dict from pairs using zip/izip, pass it to dict()

  • Count with a dict:

    • collections.defaultdict
    • collections.Counter
  • Group with dicts:

    • dict.setdefault: d.setdefault(key, []).append(name)
    • collections.defaultdict(list)
  • Is dict.popitem() atomic?

    • Yes. It’s thread-safe!!
  • Linking dicts:

    defaults = {'a': 1, 'b': 2}
    d = defaults.copy)(
    d.update(os.environ)
    d.update(cli_args)
    
    • Python3 : ChainMap(cli_args, os.environ, defaults)

Improving Clarity

  • Clarify func calls w/ kwargs
    • hours of programmer time > microseconds of performance
  • Everywhere you use tuples use collections.namedtuple instead
  • Use sequence unpacking instead of indexing!
  • Use tuple packing/unpacking for multiple variables (state, assignment in one)
    • x, y = 0, 1 vs. x = 0; y = 1
    • Simultaneous state updates!

Efficiency

  • Don’t use + to concatenate, use .join()
  • Don’t use pop, insert, del to update lists; use collections.deque

Decorators & Context Managers

  • Separate business logic from admin logic

    • business: Open URL, return page
    • admin logic: cache lookup
    • from functools import lru_cache (Python 2.7, 3.x)
  • Factor out temporary contexts

    • If you’re repeating setup/teardown, use context managers
    • __enter__, __exit__, with statement
    • Release locks using try..finally (or puppies die every time)
      • Or with lock BOOM!
  • with irgnored(OSError) (Python 3.4):

    from contextlib iport contextmanager
    @contextmanager
    def ignored(*exceptions):
        ## do a thing...
    
  • with redirect_stdout(f): (not even real yet!)

Expressive One-Liners

  • Don’t put too much on one line; don’t put too little either...
  • One logical line of code equals one sentence in English.
    • No run-on sentences (statements) !
  • List comprehensions/generator expressions are more declarative.
  • Everywhere you use [] (list comp) try to use genexp instead