Confused with methods

S

Steven Bethard

jfj said:
I think the problem is that you know python so well that you are used
to the way things are and everything seems natural the way it is.
For a newbie, the behaviour I mentioned seems indeed a bit inconsistent.
"Inconsistent" not as in mathematics but as in "wow! I'd thought this
should work like this". Like you have a perception of the language
and then this feature changes everything. It's a different kind of
"inconsistency" and it doesn't give python a bad name or something,
nor does it break the mathematical laws of the universe.

Yup, this kind of discovery happens all the time. When you ask about it
though, you should try to be clear that you're asking a question, not
making an assertion. Your post said things like:

....this is not possible...
....we prove that it is indeed a function...
....Isn't that inconsistent?...

This makes you sound very certain of yourself. If you're willing to
acknowledge that your understanding of Python is incomplete and ask
questions instead of making assertions, you'll get a lot fewer hostile
responses to your posts.

For your benefit, and the benefit of others who make this same mistake,
I'll rewrite your original post in a manner that won't seem so
self-important and confrontational[1].

Here's your original post:

----------------------------------------------------------------------
I don't understand.
We can take a function and attach it to an object, and then call it
as an instance method as long as it has at least one argument:

[snip example assigning function to class]

However this is not possible for another instance method:

[snip example assigning instancemethod to class]

Python complains that 'foo() takes exactly 2 arguments (1 given)'.
But by calling "b.foo(1)" we prove that it is indeed a function which takes
exactly one argument.

Isn't that inconsistent?
----------------------------------------------------------------------

And here it is rewritten to sound less confrontational:

----------------------------------------------------------------------
I don't understand.
I can take a function and attach it to an object, and then call it
as an instance method as long as it has at least one argument:

[snip example assigning function to class]

But I don't know how to do the same thing when I get the function from
an instance:

[snip example assigning instancemethod to class]

Python complains that 'foo() takes exactly 2 arguments (1 given)'.

Can someone explain this behavior to me? How would I get a function
from an instance and assign it to a class?
----------------------------------------------------------------------

I've left most of the terminological errors in the question since they
were probably inevitably part of the question. Note however, that my
rewrite of your post makes it clear that you are asking questions, not
making assertions. If you don't make assertions about things you don't
fully understand, you'll have a much easier time on this newsgroup.

Steve

[1] This was probably not the intended air, but that's how it came across.
 
F

Fredrik Lundh

jfj said:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Oops!!!
I think it would be more obvious to somebody who doesn't know
the python internals, to say:
# take the callback from A and install it to DSWC
u=DoSomethingWithCallback( A.callback)

that's not the same thing.
u=DoSomethingWithCallback (A().callback.im_func)

that's not the same thing.
u=DoSomethingWithCallback (A().im_class.callback)

that's not the same thing.

if you cannot tell the difference between a class and an instance, you should
spend more time learning how Python works, and less time telling everyone
how things can be made more "obvious".

</F>
 
J

jfj

Alex said:
One can say whatever one wishes, but saying it does not make it true.

One can say that x is a green frog, but that's false: x is a
boundmethod.

One can say that x is a function, but that's false: x is a boundmethod.

One can say that x is a spade, but that's false: x is a boundmethod.

I understand that a function and a boundmethod are *different* things.
For one a *boundmethod* has the attributes im_self, im_class, which
a function does not have (a green frog neither). Thus they are not
the same thing.

HOWEVER, what I ask is WHY don't we set the tp_descr_get of
the boundmethod object to be the same as the func_descr_get???
Or WHY do they *have* to differ in this specific part?

I quickly looked at the source of python and it seems that a
one-liner would be enough to enable this. So it's not that it
would be hard to implement it, or inefficient.

A bound method would *still* be a boundmethod.
We could additionally have:
<boundmethod of <boundmethod of <boundmethod of....<__main__.A
instance at 0x>>>

If there a good reason that the __get__ of a boundmethod does not
create a new boundmethod wrapper over the first boundmethod?


G.
 
J

jfj

Hello Diez.
I sent a reply to the previous message requesting an example of
what would break, but unfortunatelly it didn't make it in python-list.
Here it is for the record [
Diez said:
If things worked as you wanted it to, that would mean that passing bound
method as argument to a class and storing it there to an instance variable
that would "eat up" the arguments - surely not the desired behaviour.


Could you please give an example of this ?

If you mean:

class A:
def f(x):
print x

class B:
pass

a=A()
B.f = a.f
b=B()
b.f() #surprise: it works!!

then that is equally "weird" as my case. "eat up" sounds
rather bad but all what will happen is an argument number
mismatch.
In fact is seems more appropriate to use a.f.im_func in this
case to "convert the bound method to an unbound one".

Maybe this happens more often?


Thanks,

G.
]
If there a good reason that the __get__ of a boundmethod does not
create a new boundmethod wrapper over the first boundmethod?


I already gave you the good reason:

class A:
def callback(self, arg):
print self, arg

def callback(arg):
print arg

class DoSomethingWithCallback:
def __init__(self, cb):
self.cb = cb

def run(self):
for i in xrange(100):
self.cb(i)

u = DoSomethingWithCallback(A().callback)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Oops!!!
I think it would be more obvious to somebody who doesn't know
the python internals, to say:
# take the callback from A and install it to DSWC
u=DoSomethingWithCallback( A.callback)
or
u=DoSomethingWithCallback (A().callback.im_func)
or
u=DoSomethingWithCallback (A().im_class.callback)

v = DoSomethingWithCallback(callback)

# would crash if your suggestion worked
u.run()
v.run()

It would complain about not enough arguments.
As it does in the case I'm confused about!
If you are after currying - look at the cookbook, there are recipes for
that.

I'm satistfied with Alex's response that it is like that for backwards
compatibility, but in Python 3000 it may be the other way around.


Thanks all.

jfj
 
J

jfj

Alex said:

I think the problem is that you know python so well that you are used
to the way things are and everything seems natural the way it is.
For a newbie, the behaviour I mentioned seems indeed a bit inconsistent.
"Inconsistent" not as in mathematics but as in "wow! I'd thought this
should work like this". Like you have a perception of the language
and then this feature changes everything. It's a different kind of
"inconsistency" and it doesn't give python a bad name or something,
nor does it break the mathematical laws of the universe.

There is no trolling involved here. Maybe wrong use of the english
language. But then again, this is the newgroups and the english
language is ill-used all the time:)


Regards,

jfj
 
A

Antoon Pardon

Op 2005-02-07 said:
Any descriptor (be it a function or otherwise) has its __get__ method
called, when _accessed_ by attribute syntax, if and only if that
descriptor is in a class. _ALL_ of Python is perfectly consistent on
this point, and if I didn't already know the kind of crazy and obviously
false assertions that you post *QUITE* consistently, I would be
astonished to see you claim otherwise. Knowing your posts, this latest
idiocy is perfectly "par for the course".

No python is not consistent and your continuous repetion doesn't
make it so. To illustrate, here the following code:

class A:
l = []
def f(): pass

a = A()
print a.l is A.l
print a.f is A.f

which produces:

True
False

"A lot of magic" is simply a stupid and imprecise way to describe "the
__get__ method gets called".

So what? That is an implementation detail.
Saying that any of this happens when the
function is CALLED is a definitely more serious mistake, since it's
absolutely obvious that the __get__ method is called when the function
(or any other attribute) is *ACCESSED* -- the call operation (on
whatever object __get__ returns) happens AFTERWARDS.

Fine, I was imprecise. But your harping on my impression doesn't
change the fact that python doesn't work consistent here.
Why you, and a few other habitual trolls, keep lowering the signal to
noise ratio of this newsgroup with your blatherings, I don't know;

Well you can think me a troll, I think you are a zealot who gets
overly defensive if the "wrong" people try to suggest python has
some failing.
I'm
sure this behavior must be giving you guys some kind of satisfaction.
Whether the damage you do to the clarity of the issues, and to the
understanding of newbies who are unfortunate enough to read and trust
the many imprecise and/or utterly false assertions you keep making,

Look we are all people, we all are imprecise at moments, including you.
But when the "wrong" people get imprecise you get into a fit on how
these people are trolls and try to get python into a bad daylight
instead of trying to understand what they really are trying to say
and reacting to that and maybe in the mean time correcting the
imprecession.

In this case the way python accesses class functions from an instance
is not consistent with how python accesses other class attributes
from an instance. I know it is designed that way and I can understand
hwy it was done. But this inconsistency can be a stumbling block for
a newcomer and I think that explaining why the inconsistency is present
is a better option than declaring there is no inconsistency.
with
totally unjustified airs of competence, is part of your jollies, or just
a side effect you don't care a whit about, I don't know either. Guess
I'll just killfile you for another month now -- wish MacSOUP had a
simple way to to permanent killfiling, since it's pretty obvious by now
that it's quite unlikely you'll even post anything worthwhile at all.

Well whether I post something that is worthwhile to you, can only be
decided by you. I sometimes have my doubts about you too.
 
A

Alex Martelli

jfj said:
I just realized that I'm trolling.

I'm glad you're retracting your earlier assertion that "There is no
trolling involved here". Everybody can err, but to admit and apologize
takes character: may I offer my warmest handshake.

Back when I was a Python newbie (and identified as such even in the
Subject of my early posts) I had my ideas about how Python should
change, too: it should grow a '__contains__' special method to let a
container optimize membership tests (the `in' operator); it should have
a specialized iterator protocol, rather than always relying on indexing
for iteration; it should be possible to subclass builtin types, e.g.
dictionary; ... you can read all about it on google, including my
request to """Please consider "IMHO"'s to be liberally inserted in what
follows, of course!-)."""

It turned out that __contains__ was already in the plans (which I did
not know about): I had even guessed the *name*! The iterator protocol
and subclassing builtin types took a bit longer to appear (and the
eventual name was __iter__ while my original idea was __enum__; and it's
still not fully possible insert a subclassed dict anywhere a dict may be
used) but eventually they did.

And yet for all of this I ended up in a flamewar with the timbot
anyway... it solved itself and we made friends, but still, I'm quite
familiar with the pickles a newbie can get into;-).


Alex
 
J

jfj

Steven said:
For your benefit, and the benefit of others who make this same mistake,
I'll rewrite your original post in a manner that won't seem so
self-important and confrontational[1].

``People who code too much tend to get authoritative'', in general.

I am an arrogant noob -- just like arrogant experts...


Inconsistenly y'rs

jfj
 
J

jfj

I just realized that I'm trolling.

We all sometimes get into a trollwar despite our intensions
(even FL). So, I would like to apologize on behalf
of all those who participated in it. I'm sorry you had to witness
that.


jfj
 
D

Diez B. Roggisch

No python is not consistent and your continuous repetion doesn't
make it so. To illustrate, here the following code:

class A:
l = []
def f(): pass

a = A()
print a.l is A.l
print a.f is A.f

which produces:

True
False

Thats only inconsistent from your POV because you refuse to accept that the
scope of a function definition does matter. And as usual its a topic of
totally unrelevant practical impact and an expression of your strangely
deeprooted desire to nitpick at such unrelevant details.

Why don't you pick something that really bothers people and see if your
skills (that I'm sure exist) can be of use there?
 
A

Antoon Pardon

Op 2005-02-08 said:
No python is not consistent and your continuous repetion doesn't
make it so. To illustrate, here the following code:

class A:
l = []
def f(): pass

a = A()
print a.l is A.l
print a.f is A.f

which produces:

True
False

Thats only inconsistent from your POV because you refuse to accept that the
scope of a function definition does matter.

It doesn't. As Alex has already explained, the above is equivallent to:

def h(): pass

class A:
l = []
f = h

a = A()
print a.l is A.l
print a.f is A.f


And such great error would surely brand you a Troll in his eyes.
Scope of definition has nothing to do with it. The only factor
that matters in this case is if the function is a class atribute
or not.
And as usual its a topic of
totally unrelevant practical impact and an expression of your strangely
deeprooted desire to nitpick at such unrelevant details.

If I told you that this detail, well not this particular one but
one that is close to it, will break one of my applications in
the transition from python 2.3 to 2.4, do you still think
it is irrelevant?

I would also argue that if a particular detail is a stumbling block
for someone to understand something it is not that irrelevant
and that claiming something is inconsistent while it is not,
is not a good way to remove such a stumbling block.

Why don't you pick something that really bothers people and see if your
skills (that I'm sure exist) can be of use there?

This did bother someone, it was a stumbling block for him understanding
what was going on.
 
D

Diez B. Roggisch

It doesn't. As Alex has already explained, the above is equivallent to:
def h(): pass

class A:
l = []
f = h

a = A()
print a.l is A.l
print a.f is A.f

So what - the difference is between bound and unbound method, which is what
were talking here about after all - so in the end, its a question of how a
bound method gets created. I'm pretty sure there are plenty of other ways
to create one - try the new module, metaclasses and what not. But that they
exist and are different from unbound methods or functions is not
inconsistent. In the same spirit you could call instance methods in
languages like java or c++ inconsistent - as the have an implicit first
argument, which "normal" functions don't have. So either way round - its a
bit of magic for having oo-style method dispatch. If you want to get rid of
it, don't use OO or at least don't use classes. Nobody prevents you from
doing that.

If I told you that this detail, well not this particular one but
one that is close to it, will break one of my applications in
the transition from python 2.3 to 2.4, do you still think
it is irrelevant?

If its not _this_ detail, its not relevant for _this_ thread. And a general
assertion that transitional changes between versions of python create
problems might be worth a discussion - but that's not what were talking
about here. Instead, we're talking about inconsistencies in _one_ certain
version of python - inconsistencies that no one except you seems to
perceive.
I would also argue that if a particular detail is a stumbling block
for someone to understand something it is not that irrelevant
and that claiming something is inconsistent while it is not,
is not a good way to remove such a stumbling block.

The OP very well understood the difference between bound and unbound
methods. His confusion was that there was no general currying mechanism
behind it that would create subsequent argument bindings if he stuffed a
method into another class. He now understands better.
This did bother someone, it was a stumbling block for him understanding
what was going on.

It did bother him because he didn't understand it in the first place - and
he now does understand it.

Well, I'm well prepared to agree to disagree with you on this. If you feel
its inconsistent, I'm not trying to convince you otherwise. But as I said
before: Even if it _is_ - its still of no practical impact. Also the OP
didn't have any further problems after seeing whats getting on. So lets
move along.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top