On Thu, 28 Apr 2005 20:57:51 -0400, Peter Hansen <[EMAIL PROTECTED]> wrote:
>Uwe Mayer wrote: >> Unfortunately I want to assign a handler function to an object and something >> like this does not work: >> >>>>>class Foobar(object): pass >> >> ... >> >>>>>a = Foobar() >>>>>def a.handler(): >> >> File "<stdin>", line 1 >> def a.handler(): >> ^ >> SyntaxError: invalid syntax > >But this does work, or something close to it: > > >>> class Foobar(object): pass >... > >>> def handler(self): >... print 'in handler' >... > >>> f = Foobar() > >>> f.handler() >Traceback (most recent call last): > File "<stdin>", line 1, in ? >AttributeError: 'Foobar' object has no attribute 'handler' > >>> > >>> import new > >>> f.handler = new.instancemethod(handler, f) > >>> f.handler() >in handler > Or you can doctor up a Foobar that treats all function attributes of its instances as methods to be bound to the specific instance, e.g., (not tested beyond what you see) >>> class Foobar(object): ... def __getattribute__(self, attr): ... sentinel = object() ... atto = object.__getattribute__(self, '__dict__').get(attr, sentinel) ... if hasattr(atto, '__get__'): return atto.__get__(self, type(self)) ... elif atto is sentinel: return object.__getattribute__(self, attr) ... return atto ... >>> f = Foobar() >>> def handler(self): print 'handler of:', self ... >>> f.handler = handler >>> f.handler() handler of: <__main__.Foobar object at 0x02F0428C> >>> f <__main__.Foobar object at 0x02F0428C> >>> f.handler <bound method Foobar.handler of <__main__.Foobar object at 0x02F0428C>> >>> f.h Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 6, in __getattribute__ AttributeError: 'Foobar' object has no attribute 'h' >>> f.h =123 >>> f.h 123 >>> f.f2 = lambda self: 'Hi' >>> f.f2 <bound method Foobar.<lambda> of <__main__.Foobar object at 0x02F0428C>> >>> f.f2() 'Hi' >>> Foobar.ordinary_method = lambda self: 'ordinary' >>> f.ordinary_method <bound method Foobar.<lambda> of <__main__.Foobar object at 0x02F0428C>> >>> f.ordinary_method() 'ordinary' Try another Foobar instance: >>> g = Foobar() >>> g.ordinary_method() 'ordinary' >>> g.handler Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 6, in __getattribute__ AttributeError: 'Foobar' object has no attribute 'handler' >>> def g_handler(self): print "g's own handler for", self ... >>> g.alias = g_handler >>> g.alias() g's own handler for <__main__.Foobar object at 0x02EF134C> BTW new.instancemethod(handler, f) seems to duplicate handler.__get__(f), leaving out the type(f) in handler.__get__(f, type(f)) that would make a bound method, which is what it is, and which could be set as attribute of anything. Note the difference between newh which sticks with the f passed to new.instancemethod, and real, which Foobar.__getattribute__ dynamically attaches to the selected instance: >>> import new >>> f.newh = g.newh = new.instancemethod(lambda self:('newh', self), f) >>> f.real = g.real = lambda self:('real', self) >>> f.newh() ('newh', <__main__.Foobar object at 0x02F0428C>) >>> g.newh() ('newh', <__main__.Foobar object at 0x02F0428C>) >>> f.real() ('real', <__main__.Foobar object at 0x02F0428C>) >>> g.real() ('real', <__main__.Foobar object at 0x02EF134C>) ^^^^^^^^^^ IOW, a plain callable has __get__ and gets bound to the instance, whereas a bound method doesn't have __get__ any more, so it gets retrieved as a plain attribute. BTW, to get an ordinary function call for a function attribute of a Foobar instance, you'd have to eliminate the function's __get__ effect one way or another, e.g. staticmethod (which really wraps the function with a descriptor, substituting its own __get__, which Foobar.__getattribute__ uses transparently) >>> def sm(firstarg='sm first arg', *args): return firstarg, args ... >>> g.sm = staticmethod(sm) >>> g.sm() ('sm first arg', ()) >>> g.sm <function sm at 0x02EE8E9C> >>> g.__dict__['sm'] <staticmethod object at 0x02E8177C> >>> g.__dict__['sm'].__get__ <method-wrapper object at 0x02F0476C> >>> g.__dict__['sm'].__get__(g) <function sm at 0x02EE8E9C> Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list