Adeel Zafar Soomro Adeel Zafar Soomro - 1 month ago 11
Python Question

In Python, partial function application (currying) versus explicit function definition

In Python, is it considered better style to:


  • explicitly define useful functions in terms of more general, possibly internal use, functions; or,

  • use partial function application to explicitly describe function currying?



I will explain my question by way of a contrived example.

Suppose one writes a function, _sort_by_scoring, that takes two arguments: a scoring function and a list of items. It returns a copy of the original list sorted by scores based on each item's position within the original list. Two example scoring functions are also provided.

def _sort_by_score(scoring, items_list):
unsorted_scored_list = [(scoring(len(items_list), item_position), item) for item_position, item in enumerate(items_list)]
sorted_list = [item for score, item in sorted(unsorted_scored_list)]
return sorted_list

def _identity_scoring(items_list_size, item_position):
return item_position

def _reversed_scoring(items_list_size, item_position):
return items_list_size - item_position


The function _sort_by_score is never called directly; instead, it is called by other single-argument functions that pass a scoring function and their lone argument (a list of items) to _sort_by_scoring and return the result.

# Explicit function definition style
def identity_ordering(items_list):
return _sort_by_score(_identity_scoring, items_list)

def reversed_ordering(items_list):
return _sort_by_score(_reversed_scoring, items_list)


Obviously, this intent is better expressed in terms of function currying.

# Curried function definition style
import functools
identity_ordering = functools.partial(_sort_by_score, _identity_scoring)
reversed_ordering = functools.partial(_sort_by_score, _reversed_scoring)


Usage (in either case):

>>> foo = [1, 2, 3, 4, 5]
>>> identity_ordering(foo)
[1, 2, 3, 4, 5]
>>> reversed_ordering(foo)
[5, 4, 3, 2, 1]


Apparent advantages of the explicit function definition style:


  1. useful functions may be defined before the more general functions are, without raising NameErrors;

  2. helper functions (e.g., scoring functions) could be defined within the function definition body;

  3. possibly easier to debug;

  4. code looks nice by virtue of "explicit is better than implicit."



Apparent advantages of curried function definition style:


  1. expresses intent of functional programming idiomatically;

  2. code looks nice by virtue of succinctness.



For defining "useful" functions, which of the two styles is preferred? Are there other styles that are more idiomatic/Pythonic/etc.?

Answer

If you want to have the curried functions as part of a public interface, use explicit function definitions. This has the following additional advantages:

  1. It is easier to assign a docstring to an explicit function definition. For partial() functions, you would have to assign to the __doc__ attribute, which is somewhat ugly.

  2. Real function definitions are easier to skim when browsing the module source.

I would use functools.partial() in a similar way to lambda expressions, i.e. for locally needed throw-away functions.

In your particular example, I'd probably use neither, drop the leading underscores and call

sort_by_score(identity_scoring, foo)

which seems the most explicit to me.