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