0

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?

  • Care about efficiency when it's on your performance-critical path, and you have profiling results that confirm it. Otherwise, go for simplicity; programmers' time costs much more than CPU time. – 9000 Feb 1 '15 at 19:58
  • The b in your Option Bs doesn't seem to have much point. Why not just do map (lambda x:x+y1+y2+y3+y4+y5, x) for B2 for instance? In general, I'd only ever use a lambda, or define a function, but never both in conjunction. – Steven Burnap Feb 1 '15 at 22:05
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'
  • When would a lambda expression be appropriate, then? When you want to use the function in more than one place? – Robert Harvey Feb 1 '15 at 19:49
  • you could use a lambda in place of b in example 1 as well. b isn't even really necessary. This is perfectly valid: def a(x, y): return map(lambda z: z+y, x) – World Engineer Feb 1 '15 at 20:23
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.