Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Python bound and unbound methods

0 views
Skip to first unread message

Jeff Clites

unread,
Oct 6, 2004, 2:10:45 AM10/6/04
to Perl 6 Internals List
Python's method call semantics allows you to look up a method of an
object as an attribute, store it in a variable, and later invoke it
like a regular function. This works similarly if you do the lookup on
the class object, but when you invoke the "function" you need to pass
in an instance as an argument. Consider:


class printWrapper:
def __init__(self, message):
self.message = message
def printMe(self):
print self.message

x = printWrapper("foo")
x.printMe() # prints foo
a = x.printMe
a() # bound method call; prints foo
b = printWrapper.printMe
b(x) # unbound method call; prints foo


Do we have plans on how we might implement this via Parrot?

To put it another way, the expression "foo.bar()" in Python doesn't
really parse as "invoke method bar on object foo", but rather as
"lookup attribute bar on object foo, and call the result as a
function". That's an incredibly flexible and compact semantics, and
let's you do stuff like this:

class omniWrapper:
def __init__(self, message):
self.message = message
def printMe(self):
print self.message
def __getattr__(self, attrname):
return self.printMe

z = omniWrapper("hello")
z.printMe() # prints hello
z.igloo() # also prints hello
z.anythingAtAll() # anything prints hello

That is, you can appear to be calling methods that aren't there at all.
It seems odd, but makes perfect sense in light of the above
description--method calls in Python are not what you might think, based
on how other languages act. But that would seem to imply that Python
would need a very different method call infrastructure than Perl --
a.b() in Python means something very different than $a.b() in Perl.
(That of course brings up questions of how things act when Python tries
to call a method on a Perl object--syntax, semantics.)

JEff

Leopold Toetsch

unread,
Oct 6, 2004, 4:11:37 AM10/6/04
to Jeff Clites, perl6-i...@perl.org
Jeff Clites <jcl...@mac.com> wrote:

> Do we have plans on how we might implement this via Parrot?

Sure.

> To put it another way, the expression "foo.bar()" in Python doesn't
> really parse as "invoke method bar on object foo", but rather as
> "lookup attribute bar on object foo

Well, there isn't much difference here. "invoke method bar" implies a
method lookup that normally checks the method cache for existing
(statically built) methods. If a method isn't found there, the dynamic
plan B comes in. And if Python code overrides a method (attribute slot)
the method cache has to be invalidated.

More fun is probably to get the same inheritance ("mro") as Python.

leo

Jeff Clites

unread,
Oct 6, 2004, 12:14:52 PM10/6/04
to l...@toetsch.at, perl6-i...@perl.org
On Oct 6, 2004, at 1:11 AM, Leopold Toetsch wrote:

> Jeff Clites <jcl...@mac.com> wrote:
>
>> To put it another way, the expression "foo.bar()" in Python doesn't
>> really parse as "invoke method bar on object foo", but rather as
>> "lookup attribute bar on object foo
>
> Well, there isn't much difference here. "invoke method bar" implies a
> method lookup that normally checks the method cache for existing
> (statically built) methods. If a method isn't found there, the dynamic
> plan B comes in. And if Python code overrides a method (attribute slot)
> the method cache has to be invalidated.

A few things though:

1) In my case of a = x.printMe, we need to be prepared to return a
function created by currying a method using that particular instance,
and for b = printWrapper.printMe we need to return a function which
does type checking on its first argument (then calls the relevant
method on it)--certainly doable, just odd.

2) I'd expect the method cache to be per-class, but Python can change
an attribute slot on a per-instance basis (as well as a per-class
basis), so we can't really use a per-class method cache (or, we need a
flag on particular instances which tell us not to use it for them).

3) I won't mention the problem of languages which allow an object to
have instance variables and instance methods of the same name (so that
in Python, "a.b" would be ambiguous if "a" is an object from such a
language).

> More fun is probably to get the same inheritance ("mro") as Python.

Yes, true, and I guess related--Python must first look for things
overridden on the particular instance, I think, even before looking at
its class.

JEff

Brent 'Dax' Royal-Gordon

unread,
Oct 6, 2004, 9:17:43 PM10/6/04
to Jeff Clites, Perl 6 Internals List
Jeff Clites <jcl...@mac.com> wrote:
> Python's method call semantics allows you to look up a method of an
> object as an attribute, store it in a variable, and later invoke it
> like a regular function.

Random note: this sounds very much like a Df^H^HC# delegate.

> This works similarly if you do the lookup on
> the class object, but when you invoke the "function" you need to pass
> in an instance as an argument. Consider:

And this sounds very much like a Perl 5 method. In light of that, the
first part sounds like a Perl 6 curried sub.

I suspect that Python will just need slightly fancy vtables for method
and attribute lookup--nothing Parrot can't handle. It might not even
need a separate vtable for the two of them, although it should
implement both for interop.

--
Brent 'Dax' Royal-Gordon <br...@brentdax.com>
Perl and Parrot hacker

There is no cabal.
[I currently have a couple Gmail invites--contact me if you're interested.]

Leopold Toetsch

unread,
Oct 7, 2004, 2:49:42 AM10/7/04
to Jeff Clites, perl6-i...@perl.org
Jeff Clites <jcl...@mac.com> wrote:

> 2) I'd expect the method cache to be per-class, but Python can change
> an attribute slot on a per-instance basis (as well as a per-class
> basis), so we can't really use a per-class method cache (or, we need a
> flag on particular instances which tell us not to use it for them).

The method cache is per class. But we have properties too. Per-instance
attributes end up as properties. If there is a flag or method cache
invalidation is a matter of taste and depends on method resolution
order.

> 3) I won't mention the problem of languages which allow an object to
> have instance variables and instance methods of the same name (so that
> in Python, "a.b" would be ambiguous if "a" is an object from such a
> language).

Well, Python has that very problem. By dynamically defining an instance
variable, a method with that same name becomes inaccessible.

>>> class A(object):
... def b(self):
... print "b"
...
>>> a=A()
>>> a.b()
b
>>> a.b=2
>>> a.b()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'int' object is not callable

> JEff

leo

Jeff Clites

unread,
Oct 7, 2004, 3:43:34 AM10/7/04
to l...@toetsch.at, perl6-i...@perl.org
On Oct 6, 2004, at 11:49 PM, Leopold Toetsch wrote:

> Jeff Clites <jcl...@mac.com> wrote:
>
>> 3) I won't mention the problem of languages which allow an object to
>> have instance variables and instance methods of the same name (so that
>> in Python, "a.b" would be ambiguous if "a" is an object from such a
>> language).
>
> Well, Python has that very problem. By dynamically defining an instance
> variable, a method with that same name becomes inaccessible.

Well, for Python itself that's not a problem per se, it's a fundamental
part of the design--there's only one slot for a given name, and it can
hold a sub or something else, but it's just one slot. (You don't really
have named methods, you just have named slots that may or may not hold
subs.) That's just the way Python objects work. But for objects coming
over from another language, you might really have separate slots for
subs v. data, but if these are accessed from Python code, you don't
have a way to specify which one you mean. It's very similar to the
namespace problem with language crossing.

JEff

0 new messages