Tim Peters firstname.lastname@example.org wrote:
... Unbound methods are used most often (IME) to call a base-class method from a subclass, like my_base.the_method(self, ...). It's especially easy to forget to write `self, ` there, and the exception msg then is quite focused because of that extra bit of type checking. Otherwise I expect we'd see a more-mysterious AttributeError or TypeError when the base method got around to trying to do something with the bogus `self` passed to it.
Well, it's not that easy to agree with. Guido replied that most such cases would raise an argument-count-mismatch exception instead. I expect that's because he stopped working on Zope code, so actually thinks it's odd again to see a gazillion methods like:
class Registerer(my_base): def register(*args, **kws): my_base.register(*args, **kws)
I bet he even presumes that if you chase such chains long enough, you'll eventually find a register() method *somewhere* that actually uses its arguments <wink>.
If type checking is important, one can always add it using decorators. Then again, I would be willing to wager that most people wouldn't add it due to laziness, until it bites them for more than a few hours worth of debugging time.
While it seems that super() is the 'modern pradigm' for this, I have been using base.method(self, ...) for years now, and have been quite happy with it. After attempting to convert my code to use the super() paradigm, and having difficulty, I discovered James Knight's "Python's Super Considered Harmful" (available at http://www.ai.mit.edu/people/jknight/super-harmful/ ), wherein I discovered how super really worked (I should have read the documention in the first place), and reverted my changes to the base.method version.
How did super() get into this discussion? I don't think I've ever used it myself, but I avoid fancy inheritance graphs in "my own" code, so can live with anything.
It was my misunderstanding of your statement in regards to base.method. I had thought that base.method(self, ...) would stop working, and attempted to discover how one would be able to get the equivalent back, regardless of the inheritance graph.
I could live with it too, but I would probably use an equivalent of the following (with actual type checking):
def mysuper(typ, obj): lm = list(o.__class__.__mro__) indx = lm.index(typ) if indx == 0: return obj return super(lm[indx-1], obj)
All in all, I'm -0. I don't desire to replace all of my base.method with mysuper(base, obj).method, but if I must sacrifice convenience for the sake of making Python 2.5's implementation simpler, I guess I'll deal with it. My familiarity with grep's regular expressions leaves something to be desired, so I don't know how often base.method(self,...) is or is not used in the standard library.
I think there may be a misunderstanding here. Guido isn't proposing that base.method(self, ...) would stop working -- it would still work fine. The result of base.method would still be a callable object: it would no longer be of an "unbound method" type (it would just be a function), and wouldn't do special checking on the first argument passed to it anymore, but base.method(self, ...) would still invoke the base class method. You wouldn't need to rewrite anything (unless you're doing heavy-magic introspection, picking callables apart).
Indeed, there was a misunderstanding on my part. I misunderstood your discussion of base.method(self, ...) to mean that such things would stop working. My apologies.