Yawar Amin wrote: > Hi Steven, > > On Saturday, January 24, 2015 at 11:27:33 PM UTC-5, Steven D'Aprano > wrote: >> [...] >> > Doesn't the traceback tell us exactly where the lambda was called >> > from? >> >> Yes (assuming the source code is available, which it may not be), but > > If the source code is not available, then you're equally unable to debug > a lambda function and a named function.
If source code to a library is unavailable, debugging is significantly more difficult, but it may still be possible. At least in the sense that you can identify the nature of the bug and develop a work-around in your own code. Obviously there needs to be *some* source code for you to edit, otherwise there's nothing for you to edit :-) Even in the absence of source code, you may still be able to report a bug to the application developer and show the full traceback. Even without source, tracebacks show the names of functions, and lambdas all share the same name: [steve@ando ~]$ cat demo.py def fail(x): f = lambda a: 1/a g = lambda a: f(a-1) return g(x) print fail(1) [steve@ando ~]$ python -m compileall demo.py Compiling demo.py ... [steve@ando ~]$ python demo.pyc Traceback (most recent call last): File "demo.py", line 6, in <module> print fail(1) File "demo.py", line 4, in fail return g(x) File "demo.py", line 3, in <lambda> g = lambda a: f(a-1) File "demo.py", line 2, in <lambda> f = lambda a: 1/a ZeroDivisionError: integer division or modulo by zero [steve@ando ~]$ mv demo.py demo-save.py # hide the source [steve@ando ~]$ python demo.pyc Traceback (most recent call last): File "demo.py", line 6, in <module> File "demo.py", line 4, in fail File "demo.py", line 3, in <lambda> File "demo.py", line 2, in <lambda> ZeroDivisionError: integer division or modulo by zero In this toy example, it is still easy to debug even without names. It's a three line function, how hard could it be? :-) But that isn't always going to be the case. [...] > True, Python's current traceback reporting doesn't tell us the exact > column number on which the exception occurred. So for example with this: [...] > So the problem is there are two lambdas in line 3, so you need to > examine them both to figure out which one caused the exception. The > simple solution to this is to just put the lambdas on different lines: > > print( > (lambda: 1)(), > (lambda: 1 / 0)() > ) > > Now you get a blindingly obvious traceback: It's blindingly obvious because it is trivial. You're still thinking about the easy cases, not the hard cases: py> def make_funcs(): ... closures = [] ... for i in range(5, -5, -1): ... closures.append(lambda x, i=i: x/i) ... return closures ... py> results = [f(5) for f in make_funcs()] Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <listcomp> File "<stdin>", line 4, in <lambda> ZeroDivisionError: division by zero That's still not a hard case, because all the closures have a very similar form and it's easy to spot that one of them divides by zero. But it demonstrates one way that line numbers alone don't help. But do understand I'm not saying that lambdas cannot be debugged. I'm saying that *function names are a useful debugging tool*, so if you take away the function name that makes debugging just that little bit harder. Not necessarily in every single case, and not necessarily hard to the point that you spend days trying to track down the error, but hard enough in enough circumstances that using lambda for arbitrarily complex functions would be a bad idea. (The same applies to comprehensions: they should be kept simple.) That shouldn't be controversial. -- Steven -- https://mail.python.org/mailman/listinfo/python-list