Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Curried class methods?

Reply
Thread Tools

Curried class methods?

 
 
Scott Lamb
Guest
Posts: n/a
 
      08-17-2006
I'm trying to dynamically generate class methods which have access to
some state passed in at creation time. (Basically as a workaround to
twisted's trial not having a way to dynamically add stuff. Plain
unittest seems to have TestSuite, but the trial runner doesn't know
about it.)

My first attempt might better illustrate this -

class Foo:
def generalized(self, ctx):
print 'my ctx is %r' % ctx

for i in ['a','b','c']:
setattr(Foo, i, lambda self: self.generalized(i))

foo = Foo()
foo.a()
foo.b()
foo.c()

but this prints "my ctx is c" three times; I'd hoped for a, b, c, of
course. After reading
<http://mail.python.org/pipermail/python-list/2004-July/229478.html>, I
think I understand why this is - "i" doesn't actually get added to each
new function's context; they just reference the global one. Even if I
do this:

def builder():
for i in ['a','b','c']:
setattr(Foo, i, lambda self: self.generalized(i))
builder()

they'll just keep a reference to the context that was made on entry to
builder() and share it, so the modifications builder() makes to i are
reflected in all three functions.

Okay, take two. I tried this:

try:
from functional import partial
except ImportError:
...partial pasted from PEP 309...

for i in ['a','b','c']:
setattr(Foo, i, partial(Foo.generalized, ctx=i))

but when I try to call foo.a(), I get this error:

Traceback (most recent call last):
File "./foo.py", line 35, in ?
foo.a()
File "./foo.py", line 25, in __call__
return self.fn(*(self.args + args), **d)
TypeError: unbound method generalized() must be called with Foo
instance as first argument (got nothing instead)

If I add a debug print to partial.__call__,

print 'partial.__call__(args=%r, kw=%r, self.kw=%r)' \
% (args, kw, self.kw)

I see:

partial.__call__(args=(), kw={}, self.kw={'ctx': 'a'})

I'd first expected foo.a() to be equivalent to Foo.a(self), but instead
it's like Foo.a(). There must be magic that does the equivalent of

class Foo:
def __init__(self):
a = partial(a, self)

for real Python functions and not for my partial object.

With this __init__ magic, I guess I have something that works. I have
to apply the partial twice, though - if I do everything in the
__init__, my new functions won't exist by the time trial's
introspection kicks in, so they'll never get called. My ugly hack has
gotten even uglier.

Does anyone know of a better way to do this?

Thanks,
Scott

 
Reply With Quote
 
 
 
 
Antoon Pardon
Guest
Posts: n/a
 
      08-17-2006
On 2006-08-17, Scott Lamb <(E-Mail Removed)> wrote:
> I'm trying to dynamically generate class methods which have access to
> some state passed in at creation time. (Basically as a workaround to
> twisted's trial not having a way to dynamically add stuff. Plain
> unittest seems to have TestSuite, but the trial runner doesn't know
> about it.)
>
> My first attempt might better illustrate this -
>
> class Foo:
> def generalized(self, ctx):
> print 'my ctx is %r' % ctx
>
> for i in ['a','b','c']:
> setattr(Foo, i, lambda self: self.generalized(i))
>
> foo = Foo()
> foo.a()
> foo.b()
> foo.c()
>
> but this prints "my ctx is c" three times; I'd hoped for a, b, c, of
> course. After reading
><http://mail.python.org/pipermail/python-list/2004-July/229478.html>, I
> think I understand why this is - "i" doesn't actually get added to each
> new function's context; they just reference the global one. Even if I
> do this:


Try this instead as the for loop

for i in ['a','b','c']:
setattr(Foo, i, lambda self, a=i: self.generalized(a))

--
Antoon Pardon
 
Reply With Quote
 
 
 
 
Carl Banks
Guest
Posts: n/a
 
      08-17-2006
Scott Lamb wrote:
> I'm trying to dynamically generate class methods which have access to
> some state passed in at creation time. (Basically as a workaround to
> twisted's trial not having a way to dynamically add stuff. Plain
> unittest seems to have TestSuite, but the trial runner doesn't know
> about it.)
>
> My first attempt might better illustrate this -
>
> class Foo:
> def generalized(self, ctx):
> print 'my ctx is %r' % ctx
>
> for i in ['a','b','c']:
> setattr(Foo, i, lambda self: self.generalized(i))
>
> foo = Foo()
> foo.a()
> foo.b()
> foo.c()
>
> but this prints "my ctx is c" three times; I'd hoped for a, b, c, of
> course.


def build(j):
setattr(Foo, j, lambda self: self.generalized(j))
for i in ["a","b","c"]:
build(i)

Each call of the the build function creates its own cell "j" that the
lambda references.


Carl Banks

 
Reply With Quote
 
Scott Lamb
Guest
Posts: n/a
 
      08-17-2006
Thanks, Antoon and Carl. Just tried your solutions - both work and are
much cleaner than mine.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Class A contains class B, class B points to class A Joseph Turian C++ 5 12-30-2005 03:24 PM
Nested Class, Member Class, Inner Class, Local Class, Anonymous Class E11 Java 1 10-12-2005 03:34 PM
A parameterized class (i.e. template class / class template) is not a class? christopher diggins C++ 16 05-04-2005 12:26 AM
Curried functions =?ISO-8859-1?Q?Holger_T=FCrk?= Python 0 06-04-2004 09:44 PM
Curried functions in JavaScript (how to employ genericly, and invisibly)? svend Javascript 6 07-25-2003 02:42 AM



Advertisments