Distinguishing attributes and methods

B

Bruno Desthuilliers

MonkeeSage a écrit :
On Dec 8, 4:11 pm, Bruno Desthuilliers (snip)

You're talking about the result of calling a.a()

No, I'm talking about the result of calling a.a - which is what a.a()
means !-)

Jordan, I of course understand what you mean - but the way you express
it is not coherent with how Python works. In Python, the expression
a.a() *is* the result of calling a.a, period.
, I'm talking about
what the attribute "a" on the object "a" is.

which is the value of expression "a.a". Whether this expression evals to
a callable object or not, and wether this callable object is actually a
method object or not is another question, mostly unrelated with the
meaning of expression 'a.a'.

Which is a callable
attribute, which by definition is called a "method" in the standard
sense [1].

Still not. The fact that an attribute is callable doesn't make it a method.
You can make a distinction between a "method object" and
"any other possible callable object," but I wasn't using such a
distinction, I was using the standard definition.

Which standard definition ? Obviously not Python's standard definition
anyway !-)
So my point holds.
When you see a.a(), because of pythons calling convention "()" you
know that "a" is a method of object "a".

No you don't. You know that a.a is callable, period.
The point is that just because the attributes are "looked up the same
way" or whatever, doesn't make them the same *kind* of attribute.

<mode="stubborn">
Yes it does : they are all of kind 'object' !-)
To
say that all attributes are the same in python muddies the water. They
are the same in a generic sense that they are attributes, but not in
their particular qualities.

Obviously not - but this is true for all known OOPL. Now from a
technical POV, there are no separate slots, no compiler-or-interpreter
special processing, nor nothing else special about 'methods', no special
type, etc - the storage and lookup mechanisms are *exactly* the same for
*all* attributes (leaving special features like __slots__ aside). All
the "magic" in 'methods' is handled by the way the function type
implements the descriptor protocol, and this can be reproduced by any
other type, because it's just *one* possible use of lookup hooks (+, in
this case, callable objects) - another possible use being the property
type. IOW, what makes the difference is the specific implementation of
the attribute's class, *not* the generic attribute storage/lookup mechanism.
Like saying "all humans are the same" --
yes, in a general sense of being human. But to leave it at that is not
very helpful.

[1] http://en.wikipedia.org/wiki/Method_(computer_science)

The second is whatever the lookup mechanism will yield for this name.

You're wrong. Python's "methods" are thin wrappers around an instance
(or class) and a function. These wrappers are "built" *at lookup time*
by the __get__ method of the function object itself when it's looked up
as an attribute of a class, thanks to the lookup mechanism and the
descriptor protocol.

Now the fact that an attribute is callable doesn't make it a "method".

Also, anyone can implement it's own callable type that will act as a
true function - that is, implement the descriptor protocol to return a
wrapper around the instance or class and the callable - without
necessarily yielding an instance of types.MethodType. This is all fairly
trivial.

Again, I am using the common definition.

This "common definition" is obviously not applicable to each and every
language - at least when it comes to implementation !-)

Mays I remind you that the OP question was about "how to distinguish
methods from attributes". And the answer is that given Python's object
model and implementation, there's no clear, definitive and unambiguous
way to do so.
I understand that you can
make an attribute callable in different ways than just the standard
machinery of "def symbol(self):" (those other techniques are what I
was referring to above by "metaprogramming"). But how it is made
callable doesn't matter (nor does how it is looked up).

The fact is that it does matter, because it's the lookup mechanism that
implements the hook used by functions to return methods when they are
used as class attributes. And it also matters because *all* this
behaviour can be reproduced without extending the function type nor
using the method type, so you can't even rely on typechecking to
distinguish a callable attribute from what is commonly known as a a method.
Once it is
callable, it fits the defintion of "method" I'm using.

Still not. May I remind you that the class is a callable attribute of an
object ? And that when used as *instance* attributes, functions remain
plain functions ? And that a class attribute can be callable without
implementing the lookup hook that would yield a method object ?
In future, I'll
try to be clear when I'm referring to something python specific or to
a general CS concept.


"Silly" in the sense that in this context, they only serve to show
that TIMTOWTDI, but don't actually change a callable attribute from
being a callable attribute ("method" in the general CS sense)

This is exactly what I'm trying to explain here : in Python, callable
attribute != method.
to being
some magical "something else".
For the purpose of distinguishing an
object variable (non-callable attribute) and an object method
(callable attribute), they don't add anything.

By your definition, the class of an object is a method. I'll let you
think about it...
 
M

MonkeeSage

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) that determine how an attribute is bound,
whether it is bound at all, whether it is even callable, 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) are
"methods," what am I missing?

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

I guess what I'm asking is, in what way is a "method" (or "function")
semantically different from a home-brewed callable I concoct and bind
to an object (or toplevel)? What is the distinction that I'm missing?

Ps. wrt your last comment, isn't a class object in essence a factory
method?

Regards,
Jordan
 
B

Bruno Desthuilliers

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.
 
S

Steven D'Aprano

So, when I say that all callable attributes (or to be more precise, all
callable attributes bound to objects other than toplevel) are "methods,"
what am I missing?

Everything that isn't a method but is callable.

class Callable(object):
def __call__(self):
return oct(id(self))


class Foo(object):
aclass = type('Parrot', (object,), {})
atype = int
ainstance = Callable()
afunction = None # this is tricky...
def __init__(self): # a method
self.afunction = lambda n: n+1
 
M

MonkeeSage

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

Thank you kindly Bruno. You're answers have been very informative. I
thought I understand how python was operating, but I see that I have
some misconceptions. I honestly did read through the reference manual
when I started learning python a couple years ago, but I'm not the
most patient person by nature, and it seems that I was so happy with a
shiny new language, that I imported some foreign concepts into the
picture and glossed over many of the details of pythons object model.
I'm going to give the "Data Model" section a thorough going-over
again, and try to pay more attention this time(!) ;)

Just as a side-note, it's interesting that even through my
misunderstandings I've been able to use python to great effect (I've
translated several fairly complex apps to python, using decorators,
CPS and other fairly "advanced" techniques, and it "Just Worked").
Heh. Nice language. :)

Anyway, thanks again for your time an patience.

Regards,
Jordan
 
B

Bruno Desthuilliers

MonkeeSage a écrit :
On Dec 10, 7:19 am, Bruno Desthuilliers <bruno. (snip)
I'm going to give the "Data Model" section a thorough going-over
again, and try to pay more attention this time(!) ;)

Also make sure you read the docs about new-style classes, the descriptor
protocol and metaclasses.
Just as a side-note, it's interesting that even through my
misunderstandings I've been able to use python to great effect (I've
translated several fairly complex apps to python, using decorators,
CPS and other fairly "advanced" techniques, and it "Just Worked").
Heh. Nice language. :)

Indeed !-)
Anyway, thanks again for your time an patience.

Thanks *you* for your patience - I'm certainly not the best teacher here !-)
 
B

Bruno Desthuilliers

Jan Claeys a écrit :
Op Sun, 09 Dec 2007 12:44:46 -0800, schreef MonkeeSage:




Well, I guess Python is a language for human being... ;-)


To conclude this discussion:

* in Python, methods are attributes
* in Ruby, attributes are methods
And this is probably the most sensible post in this thread !-)
 
F

Florian Diesch

MonkeeSage said:
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) that determine how an attribute is bound,
whether it is bound at all, whether it is even callable, 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) are
"methods," what am I missing?

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

I guess what I'm asking is, in what way is a "method" (or "function")
semantically different from a home-brewed callable I concoct and bind
to an object (or toplevel)? What is the distinction that I'm missing?



--8<---------------cut here---------------start------------->8---
#!/usr/bin/env python

class Foo(object):

def __init__(self):
def func(*args):
return str(args)
self.a=func

def b(*args):
return str(args)

@classmethod
def c(*args):
return str(args)



f=Foo()
print f.a(1) # just a callble
print f.b(1) # an instance method
print f.c(1) # a class method
--8<---------------cut here---------------end--------------->8---



Florian
 
B

Boris Borcic

MonkeeSage said:
what am I missing?

To my eyes, when you write:
>I think it muddies the water to say that a.a() and a.a are the same
>thing--obviously they are not. In the common case, the first is a
>method, and the second is a variable.

What you are most obviously missing is what's shown by

b=a.a
b()

IOW I am tempted to make the prediction that you never use bound methods as
values :)

Cheers, BB
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top