Do you use Python mostly for its functional or object-oriented features? [closed]

I mostly use Python using object-oriented and procedural styles. Python is actually not particularly well-suited to functional programming.

A lot of people think they are writing functional Python code by using lots of lambda, map, filter, and reduce, but this is a bit over-simplified. The hallmark feature of functional programming is a lack of state or side effects. Important elements of a functional style are pure functions, recursive algorithms, and first class functions.

Here are my thoughts on functional programming and Python:

  • Pure functions are great. I do my best to make my module-level functions pure.

    • Pure functions can be tested. Since they do not depend on outside state, they are much easier to test.
    • Pure functions are able to support other optimizations, such as memoization and trivial parallelization.
  • Class-based programming can be pure. If you want an equivalent to pure functions using Python classes (which is sometimes but not always what you want),

    • Make your instances immutable. In particular, this mainly means to make your methods always return new instances of your class rather than changing the current one.
    • Use dependency injection rather than getting stuff (like imported module) from global scope.
    • This might not always be exactly what you want.
  • Don’t try to avoid state all together. This isn’t a reasonable strategy in Python. For example, use some_list.append(foo) rather than new_list = some_list + [foo], the former of which is more idiomatic and efficient. (Indeed, a ton of the “functional” solutions I see people use in Python are algorithmically suboptimal compared to just-as-simple or simpler solutions that are not functional or are just as functional but don’t use the functional-looking tools.)

  • Learn the best lessons from functional programming, for example mutable state is dangerous. Ask yourself, Do I really want to change this X or do I want a new X?

    • One really common place this comes up is when processing a list. I would use

      foo = [bar(item.baz()) for item in foo]
      

      rather than

      for index, _ in enumerate(foo):
          foo[index] = bar(foo[index].baz())
      

      and stuff like it. This avoids confusing bugs where the same list object is stored elsewhere and shouldn’t be changed. (If it should be changed, then there is a decent chance you have a design error. Mutating some list you have referenced multiple places isn’t a great way to share state.)

  • Don’t use map and friends gratuitously. There is nothing more functional about doing this.

    • map/filter are not more functional than list comprehensions. List comprehensions were borrowed from Haskell, a pure functional language. map and especially filter can be harder to understand than a list comprehension. I would never use map or filter with a lambda but might if I had a function that already existed; I use map a decent bit.
    • The same goes for itertools.imap/ifilter compared to generator expressions. (These things are somewhat lazy, which is something great we can borrow from the functional world.)
    • Don’t use map and filter for side effects. I see this with map a lot, which both makes hard-to-understand code, unneeded lists, and is decidedly not functional (despite people thinking it must be because of map.) Just use a for loop.
    • reduce is confusing except for very simple cases. Python has for loops and there is no hurt in using them.
  • Don’t use recursive algorithms. This is one part of functional programming Python just does not support well. CPython (and I think all other Pythons) do not support tail call optimization. Use iteration instead.

  • Only use lambda when you are defining functions on the fly. Anonymous functions aren’t better than named functions, the latter of which are often more robust, maintainable, and documented.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)