Fredrik Lundh <[EMAIL PROTECTED]> wrote: ... > Alex Martelli wrote: > > >> Traceback (most recent call last): > >> File "mymodule.py", line 9, in somefunction > >> someobj.bar() > >> ... zero or more lines ... > >> File "somelibrary.py", line 3, in bar > >> raise NotImplementedError("must implement abstract method bar") > >> NotImplementedError: must implement abstract method bar > >> > >> you have to look at the last line of a traceback to find the error > >> message, and the offending module/method is two lines above that. > > > > The offending module is the one which instantiates a class it shouldn't > > instantiate -- a class which isn't made concrete by overriding all > > methods which need to be. What is that module? > > in real life, it's mymodule.py or mylib.py, in code that you wrote very > recently.
In my experience, it ain't necessarily so. Maybe I happen to work more than you do with, for example, people who've had indoctrination into "the proper ways to do OOP" (meaning C++ or Java) -- indeed I've found that wanting to make abstract classes with methods which raise exceptions, rather than just omitting the methods (and thus getting an AttributeError if anybody tries calling them on instances of subclasses which lack them) has a good correlation with people with the mindset typically coming from such doctrine. Such people write modules which define abstract classes and also the functions that receive instances of such abstract classes (sometimes they even check for that with isinstance!) and call methods on them -- never, in practice, will the same 'mymodule.py' that calls someobj.bar() be the one which created 'someobj'; rather 'someobj' will be an argument to 'somefunction' -- so you need to continue the study up the stack of calls. I'm not saying "it can't be done"! I'm saying it's quite likely to take EXTRA MINUTES (that's ALL I'm claiming, remember: so, your counterclaim is that such a search *hardly ever takes more than an extra 119 seconds*!!!) to find out where the should-be-concrete class is defined and instantiated, starting from the first call to one method it has wrongfully left un-overridden, compared to the case where the class statement itself, or the instantiation, raise the exception. As for the "code you've written recently": maybe, IF that abstract class and supporting infrastructure never changes. If your application-level code uses frameworks which change (never a pleasant situation, but it does often happen), then it's quite likely the *framework* has changed recently, adding a deuced new 'bar' method that now you're supposed to override, too. Again, you must find out where you defined the subclass which happens to be the class of 'someobj'. Again, I would NOT be surprised if it took 121, even 122 seconds... or (gasp!) occasionally even more! > > The error is generally not the calling of 'bar' on someobj: someobj > > arrives as a argument to somefunction from somewhere -- the caller of > > somefunction is quite often innocent, in turn -- who BUILT someobj, by > > instantiating which class? I think `minutes' is a very fair (not at all > > pessimistic) assessment of the time it will generally take to find out. > > you can blather for years if you want to, but your arguments are just > another variant of the "you cannot use whitespace for indentation" stuff > we've all seen from time to I'm not saying you *cannot* do anything: I'm claiming that, if you do things in a slightly different way, it will often save you 120 or more seconds of time in finding out where you made a mistake. If you think it's worth the bother of putting in 'empty' abstract methods which raise NotImplementedException (rather than saving the time in the first place by just omitting them), you must be convinced they help productivity -- e.g. make it faster to find errors, compared to the easier-to-obtain effect of getting an AttributeError. How? And how comes a more precise indication of where the override was not done (ideally by raising at the class statement, but instantiation time isn't all that much worse) appears in your opinion to give NO further added value, not even two minutes' worth? > time; it's trivial to come up with a large number of theoretical problems > with any given approach, but in real life, for real-life programmers, > using real-life libraries designed by real-life developers, it's simply > not the problem you want it to be. I don't "want" anything in particular. I _have_ observed people spending over 120 seconds finding out where the errant class was defined and what methods it was missing -- with real-life everythings; just the same amount of time they'd have spent without the silly NotImplementedError to "help", just by reasoning from AttributeError. > but not that I'm going to convince you, now that you've spent 15,000 > characters on this topic... Characters are cheap. On the other hand, I can't see how you can convince me that what I've observed (and common sense confirms) is an illusion, that one can't waste two minutes finding exactly where the errant class was defined. Since it takes about 4 minutes to code that metaclass, if twice in a project's lifetime, 2 minutes each time are saved, one breaks even; if three times, one's gaining. This doesn't take into account the large amount of times wasted on this incredibly silly thread, of course, but hey, I disclaim any responsibility for it: I posted a sketch of a dozen lines of code to solve a real-life problem somebody seemed to be having, and found myself unexpectedly under attack for 'posting a magnum opus', 'blathering for years', and now even arguing against using whitespace for indentation. Definitely not the c.l.py I recalled; if that's what one can expect, these days, for posting a dozen lines of HTH code -- amount of thanks or any expression of gratitude a nice round zero, amount of flames and direct attacks as high as I've gotten so far -- I guess I'm not going to stay around all that long this time. Alex -- http://mail.python.org/mailman/listinfo/python-list