mk a écrit :
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?

answered below - read on, young padawan <g>

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?

Indeed.

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 <blush />

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)?

Yes, but it's not bound to a Foo instance.

So, why is it that type(Foo.bar) != type(Foo.__dict__['bar']) ?

 >>> type(Foo.__dict__['bar'])
<type 'function'>

Yeps. That's the function object created by the def statement. Just a plain old function - expect it's an attribute of class object "Foo".

 >>> type(Foo.bar)
<type 'instancemethod'>

instancemethod - now that's something new.

Don't let the "<unbound method Foo.bar>" fools you - it's just instancemethod.__repr__ that issues different wording according to whether the instancemethod instance is bound or not.


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?

s/call/lookup/

If it's looked up on the class, there's no instance to pass to __get__.


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?

Having access to the class is handy when you don't have the instance. The point is mostly to let the descriptor know how it has been looked up and take appropriate decisions based on this - for a definition of "appropriote" that depends on what the descriptor is intended for . Remember that this mechanism provides the generic support for all kind of computed attributes - methods, properties, and whatever you can write yourself.

Python is science, I gather: an answer to one question bears another 10 questions.

That's the case with most technical domains - until you solved enough of the puzzle to start and see the big picture.

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?

In that case, it's quite simple: function.__get__ is a method of the function type, so it's called with 'self' as first argument !-)

Aside from rejected PEP (http://www.python.org/dev/peps/pep-3130/) I don't see the way of accessing itself outside globals()

You're confusing the function instance itself with the content of the def statement's block. The code within the def statement's block has no access to the function instance that will be built from it, but other methods of the function instance are, well, ordinary methods.

(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)

it receives itself, yes. Ordinary method call, nothing magical here - well, almost...!-).

as an argument, like in your example implementation below?

Exactly.

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.

Now you know. As far as I'm concerned, I do find this whole mechanism to be a thing of beauty - instead of special-casing methods, you just use plain functions and the much more generic descriptor protocol to achieve the same result - with much more flexibility.

!!THANKS!!

My 2 cents...

Well, Bruno -- that was more like $200!

Ok, make it 3 cents then !-)

More seriously, all this is explained in Raymond Hettinger's excellent 'descriptor howto' article, that is linked from the official doc - and that's how I learned all this.
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to