I am never sure which of these is better form:
Option A
def a(x,y):
def b(z): return z+y
return map(b, x)
print a([10,20], 5)
Option B
def b(z,y): return z+y
def a(x,y):
return map(lambda x: b(x,y), x)
print a([10,20], 5)
Suppose that b() is ONLY ever called from inside a().
I know Option B is more efficient because it only declares b() once, and then the variable y is just passed as a context variable. But Option A seems to be simpler syntax, eliminating the need to construct a lambda, and simplifying the interface of b(). Suppose further that there could actually be many context arguments. The complexity blows up on the interface of b():
Option A2:
def a(x,y1,y2,y3,y4,y5):
def b(z): return z+y1+y2+y3+y4+y5
return map(b, x)
print a([10,20], 5,6,7,8,9)
Option B2:
def b(z,y1,y2,y3,y4,y5): return z+y1+y2+y3+y4+y5
def a(x,y1,y2,y3,y4,y5):
return map(lambda x: b(x,y1,y2,y3,y4,y5), x)
print a([10,20], 5,6,7,8,9)
Option A2 is far fewer characters.
Thoughts?
2
Per the Zen of Python: simple is always better than complex. I’d pick the first option on the principle that it is vastly easier to understand and thus easier to maintain. Generally speaking, in Python, one worries more about the ease of use of the code than the efficiency of the code.
If you want to simplify long lists of arguments, use *args:
4.7.3. Arbitrary Argument Lists
Finally, the least frequently used option is to specify that a function can be called with an arbitrary number of arguments. These arguments will be wrapped up in a tuple (see Tuples and Sequences). Before the variable number of arguments, zero or more normal arguments may occur.
def write_multiple_items(file, separator, *args):
file.write(separator.join(args))
Normally, these variadic arguments will be last in the list of formal parameters, because they scoop up all remaining input arguments that are passed to the function. Any formal parameters which occur after the *args parameter are ‘keyword-only’ arguments, meaning that they can only be used as keywords rather than positional arguments.
>>> def concat(*args, sep="/"):
... return sep.join(args)
...
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")
'earth.mars.venus'
2
Do you need the efficiency more than the simplicity, or the simplicity more than the efficiency?
Use what makes sense for your specific application. If you need the simplicity more than the efficiency, then use option A. If you need the efficiency more than the simplicity, then use option B.
Code profilers can help immensely in this regard. Programmers are notoriously bad at guessing how expensive a given operation is; a code profiler can give you evidence that will help you determine the real cost of a computation, and help you make a better, more informed choice.