Introduction to the problem
Hi, I have recently switched to Python programming language from Mathematica because I would like to make my code portable and more powerful. I studied the Functional Programming HOWTO guide and I started playing around with higher-order functions.
What I find confusing for a newcomer on the functional paradigm of the Python language is the default behavior, i.e. the standard execution, of higher-order functions. For example when you apply map()
over a sequence you get back a map object (heck see the comments below):
odd = lambda x : x%2!=0
lis = [1, 6, 2, 5, 9, 4]
map(odd, lis)
Out[171]: <map at 0x19e6a228e48>
Mathematica users would expect to "thread" odd()
over a list and the result of the evaluation would be a list of booleans. In python you have to materialize the result using the list()
constructor e.g.:
list(map(odd, [1, 6, 2, 5, 9, 4]))
Out[172]: [True, False, False, True, True, False]
What I am missing
One of the things I am missing in Python is a list-able attribute for thread-able functions. Indeed this is a core feature in Wolfram Mathematica language. But the beautiful thing in Python is that everything is an object (everything is an expression in Wolfram Language) including functions therefore I can change how function objects behave by passing a keyword argument to indicate whether I want the function to return a generator/iterator or the full materialized result.
Specifications for a full answer
So this is the question to ask here for advanced core developers of the Python Language. Continuing the example above, odd()
is a function that takes one argument, if PyFunctionObject
had, let's say, a materialize
and listable
attribute I would expect to write
odd.listable = True
odd.materialize = True
odd(1, 6, 2, 5, 9, 4)
Out[172]: [True, False, False, True, True, False]
odd(6)
Out[173]: False
Or switch to the default behavior you get now when you map() ...
odd.listable = True
odd.materialize = False
odd(1, 6, 2, 5, 9, 4)
Out[31]: <generator object Listable.__call__.<locals>.<genexpr> at 0x000001F3BBF1CC50>
References
I have searched stackoverflow for similar questions and the closest I have found is this one: Automatically use list comprehension/map() recursion if a function is given a list. The answer of David Robinson is based on decorators. Back in 1999 Michael Vanier posted also this answer here which is a class based solution of this problem.
My question is slightly different because I am asking how you can tweak the function object at a low level so that you get the desirable behavior I wrote about. I am also arguing here that this feature will make functional programming in Python easier for newcomers and a lot more fun, For a start, they do not need to learn about generators and iterators. If there is already such discussion in the road map to Python please let me know.