Distinguishing attributes and methods
Bruno Desthuilliers
bruno.42.desthuilliers at wtf.websiteburo.oops.com
Mon Dec 10 08:19:38 EST 2007
MonkeeSage a écrit :
> It seems that I've got a short-circuit somewhere here. I understand
> that everything is an object and the the storage/lookup system is
> object-agnostic, and that it is only the descriptors (or "tags" as I
> called them generically)
"descriptor" is a protocol - an interface if you prefer. It's a way for
a class attribute to hook into the lookup mechanism, and it's
implemented by the property type - to provide a basic support for
computed attributes - and the function type - to provide the machinery
that turns a function into a method.
> that determine how an attribute is bound,
> whether it is bound at all, whether it is even callable,
An object is callable if it implement the __call__ method (for the
commonly admitted definition of 'method' !-).
> and so forth.
> So, when I say that all callable attributes (or to be more precise,
> all callable attributes bound to objects other than toplevel)
You mean "other than a module" ?
> are
> "methods," what am I missing?
All callable attributes that are either bound to an instance or don't
implement the descriptor protocol the way the function type do.
> You said "the difference [between a callable attribute and a method]
> is the specific implementation of the attribute's class"...but this
> almost sounds like type-by-primitive
It isn't.
> (a method is a method when it
> derives from a certain base class), or type-by-behavior (a method is a
> method when it behaves in a certain way, e.g., responds in a certain
> way to a query).
Bingo.
> Is this correct? Shouldn't it be type-by-capability/
> interface--i.e., it implements the protocol of a callable, therefore,
> formally, it is not meaningfully different from any other callable
> (quacks like a duck and all)?
The answer is in how the function type implements the descriptor
protocol. For an attribute to "become" a method when looked up, this
attribute has to implement the descriptor protocol so that it's __get__
method returns either a BoundMethod (or any equivalent) when looked up
on the instance and an UnboundMethod (or any equivalent) when looked up
on the class (I'll save you the details about classmethods etc).
Now since the method type is mostly trivial to implement, the fact that
an attribute lookup doesn't return an instance of Method doesn't
necessarily imply it's not one - so the truth is that an attribute is a
method if it behaves like one !-)
> I guess what I'm asking is, in what way is a "method" (or "function")
Python's 'methods' are really thin wrappers around an object, it's class
and a function. In the common use case, one of these wrappers is
instanciated each time you lookup a function that's a class attributes.
> semantically different from a home-brewed callable I concoct and bind
> to an object (or toplevel)? What is the distinction that I'm missing?
Implement your own callable that doesn't implement the descriptor
protocol, bind it to a class, instanciate your class, lookup this
attribute. You'll get the original attribute, not a method. Or bind a
function to an *instance*, and look it up - here again, you wont get a
method, but the original function object.
Now you can of course label this a static method if you want !-)
If you want a custom callable to be usable as a method, you have to
implement the descriptor protocol like the function type do.
> Ps. wrt your last comment, isn't a class object in essence a factory
> method?
Not quite - even if you can use it that way. In fact, the real factory
method is the __new__ method of the class - that is, the proper constructor.
A class object is an object that is responsible for:
* creating instances of itself (and as such, it is indeed a factory -
but a factory object, not a factory method)
* providing class attributes and mro to these instances (lookup rules
here: a name not found in the instance's __dict__ will be looked up in
the class, then in classes in the mro - unless of course the class
implements __getattr__ or __getattribute__, in which case all bets are
off).
caveat : all this describes the 'new-style' object model. The 'classic'
('old-style') object model works a bit differently.
> Regards,
> Jordan
More information about the Python-list
mailing list