On Sat, Mar 16, 2013 at 2:27 PM, Rick Johnson <rantingrickjohn...@gmail.com>wrote:
> > [snip junk] > We don't need multiple layers of traces for NameErrors. Python does not > have *real* global variables; and thank Guido for that! All we need to know > is which module the error occurred in AND which line of that module > contains the offensive lookup of a name that does not exist. > [snip more junk] 2 comments here. 1) Where's the consistency?? NameError is an exception. All other exceptions get full tracebacks. A NameError is not special enough to deserve special treatment (zen of Python? PEP 8? I don't remember). If you like the full traceback (like I do), it's there. If you just want the error, look at the last frame only. ==== Example where you want a full traceback ==== Pyflakes doesn't catch all NameErrors. If you don't set all of an object's possible attributes inside its constructor, but some are applied later-on (i.e., when they are needed, like in some sort of specialized setup routine that you only call in certain circumstances), then you can benefit from a full traceback even for a NameError. Consider the DataSet class below: import numpy as np from scipy.stats.kde import gaussian_kde as kde class DataSet(object): def __init__(self, data): self._dataset = np.asarray(data) def setup_kde(self): "Set up KDE. Do not do by default since it is expensive for large data sets" self.kde = kde(self._dataset) def resampled(self): return DataSet(self.kde.resample()) In this case generating the KDE can become time- and RAM-consuming for large data sets, so it's worthwhile to only generate the KDE if you actually plan on doing something with that requires it. If you call resampled before setup_kde, you get a NameError, and it would be helpful to have the full traceback when debugging. Yes, you can get around having the 'non-trivial' NameError, but having the full traceback if someone _did_ write code like this makes your job a hell of a lot easier to debug if you don't have to go stack tracing yourself. And for a large project with multiple coders that is built in stages and has functionality added as it's needed, this type of situation is not at all unusual. While one approach is to take to the (email) streets and proclaim how incompetent all coders that came before you truly were and that such a project is not worth modifying in view of their ineptitude, the approach that does _not_ lead to your firing would benefit from a full NameError traceback. Go ahead and fire away about how stupid I am for the suggestion anyway, though. 2) Fine. You don't like long tracebacks for NameErrors, write a 8-line module that you import at the top of every program (like division from __future__ if you work with Python 2 like I have to): --- file ricksstupididea.py --- import sys, traceback def excepthook(exctype, value, tb): if exctype is NameError: print 'Traceback (only printing last frame):' print ' File "%s", line %d, in %s\n %s' % traceback.extract_tb(tb).pop() print 'NameError: %s' % value else: sys.__excepthook__(exctype, value, tb) sys.excepthook = excepthook --- end ricksstupididea.py --- Once you do this, you get your special behavior for NameErrors like you want. Observe, padawan: -- begin nameerror.py -- import ricksstupididea def func1(x): return func2(x) def func2(x): return func3(x) def func3(x): return func4(x) def func4(x): return noname func1(1) $ python noname.py Traceback (only printing last frame): File "noname.py", line 12, in func4 return noname NameError: global name 'noname' is not defined -- begin divzero.py -- import ricksstupididea def func1(x): return func2(x) def func2(x): return func3(x) def func3(x): return func4(x) def func4(x): return x / 0 func1(1) $ python divzero.py Traceback (most recent call last): File "divzero.py", line 14, in <module> func1(1) File "divzero.py", line 3, in func1 return func2(x) File "divzero.py", line 6, in func2 return func3(x) File "divzero.py", line 9, in func3 return func4(x) File "divzero.py", line 12, in func4 return x / 0 ZeroDivisionError: integer division or modulo by zero GvR's time machine strikes again. The only bad thing about this approach is that you have to actually write that extra 8 lines of code, and I get to keep the behavior I like rather than being forced into the (inconsistent) behavior you would prefer I use instead. But since the 8 lines has been provided to you here free of charge, the only real cost for you is how I like my NameErrors given to me. I hereby leave you enlightened. </rant> Jason
-- http://mail.python.org/mailman/listinfo/python-list