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 -- http://mail.python.org/mailman/listinfo/python-list