mk wrote: > Bruno Desthuilliers wrote: >>> Thanks, that worked. But in order to make it work I had to get rid of >>> 'self' in print_internal_date signature >> >> Indeed. Using it that way, the print_internal_date will not be wrapped >> in a method object. > > Hold on! How does Python know what to wrap and what not to wrap, > assuming of course programmer doesn't use @classmethod or @staticmethod? > Bc self has no special significance, it's just a (strong) convention, > Python can't know what's the first argument of a function supposed to > be, self or regular argument, and therefore it has no way of > differentiating between functions (defined in class body) designed to > become methods and those that are not? > > Where can I read on Python internals like this (aside from post of > yours, that is)? Bc frankly skimming http://docs.python.org/reference/ > didn't give me impression that a lot on the subject is there (well > there's some, I found smth akin to your explanation below, although > yours is way more readable)? > > Thanks for explanation below -- I'm going to ask some related questions. > >> Mmmm... Let's try to explain the whole damn thing. It's really (and IMHO >> beautifully) simple once you get it, but I agree it's a bit peculiar >> when compared to most mainstream OO languages. >> >> The first thing is that the def statement *always* yield a function >> object. Always. If you don't believe it, try the following snippet: >> >> class Foo(object): >> def bar(self): >> return "baaz" >> >> print Foo.__dict__.keys() >> print type(Foo.__dict__['bar']) > > Just one thing here: > >>>> Foo.bar > <unbound method Foo.bar> > > Huh?! Why does it say 'unbound' method? Shouldn't that be bound method > (bound to Foo, that is)? > No. The "unbound method" means it's a callable class attribute. The significance of "unbound" is that no specific instance is attached.
>> So, why is it that type(Foo.bar) != type(Foo.__dict__['bar']) ? > >>>> type(Foo.__dict__['bar']) > <type 'function'> >>>> type(Foo.bar) > <type 'instancemethod'> > > instancemethod - now that's something new. > Well "instancemethod" is just the type of the attribute. If you create a Foo instance, its bar method also has type instancemethod, even though it's a *bound* method: >>> foo = Foo() >>> foo <__main__.Foo object at 0x7ff2a16c> >>> foo.bar <bound method Foo.bar of <__main__.Foo object at 0x7ff2a16c>> >>> type(foo.bar) <type 'instancemethod'> >>> Note that it's only when the method is looked up *from an instance of the class* does the interpreter create the bound method. And remember that this is behavior that's specific to Python 2. > >> The >> answer is : attribute lookup rules and the descriptor protocol. >> >> To make a long story short, the descriptor protocol specify that, when, >> during an attribute lookup, a name resolves to a class attribute AND >> this attribute has a __get__ method, then this __get__ method is called >> (with either the instance or None and the class itself as arguments) > > Depending, I assume, on whether this is instance call | class method > call, respectively? > Yes. > Hmm why does the __get__ receive class as argument on top of instance | > None? After all, when having an instance, the class can always be found > by instance.__class__ ? Is this for sake of class methods? > When Bruno wrote "... AND this attribute has a __get__ method ...", the __get__method has to be defined on the attribute's class - the interpreter won't even look at the instance when trying to resolve the reference. But inheritance, of course, means that the same __get__ method may be used by several classes, and when there is no instance the specific (sub)class in question must be identifiable. So you got that right. > Python is science, I gather: an answer to one question bears another 10 > questions. > Yes, but it isn't quite "turtles all the way down". Ultimately the behavior we are discussing is hard-wired into the interpreter at the __getattribute__ level. >> and whatever it returns becomes the result of the attribute lookup. This >> mechanism is what provides support for computed attributes. >> >> Now the trick is that the function type do implement the descriptor >> protocol. So when a function is an attribute of a class object and you >> try to access it as an attribute of either the class itself or an >> instance of the class, it's __get__ method is called with the instance >> (or None) and the class. > >> Having access to itself (of course), > > Quick question: how does a function access itself? Aside from rejected > PEP (http://www.python.org/dev/peps/pep-3130/) I don't see the way of > accessing itself outside globals() (and even then how would a function > know its name -- well it shouldn't care about it really, as function > object doesn't care how it's labelled, right?). Or does in "real Python" > func's __get__ receive its own function (func) as an argument, like in > your example implementation below? > The function is an object of type function, so the lookup triggers a call to the __get__() method of the function's class, providing the instance (that is the function that is being called) as the first argument. >> the >> instance (if there's one) and the class, it's easy for it to wrap all >> this into a method object. Which is itself a callable object, that when >> called mostly inject the instance as first object in the argument's list >> and returns the result of calling the wrapped function object. > > Aha! So that's the mechanism that makes self magically appear in an > argument list! I always wondered how it worked. !!THANKS!! > > >> My 2 cents... > > Well, Bruno -- that was more like $200! > I agree, this is stuff that's hard to understand, and Bruno's explanations are most helpful. regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 PyCon is coming! Atlanta, Feb 2010 http://us.pycon.org/ Holden Web LLC http://www.holdenweb.com/ UPCOMING EVENTS: http://holdenweb.eventbrite.com/ -- http://mail.python.org/mailman/listinfo/python-list