anonymous function objects?
Bengt Richter
bokr at oz.net
Fri Apr 29 08:16:28 EDT 2005
On Thu, 28 Apr 2005 20:57:51 -0400, Peter Hansen <peter at engcorp.com> 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
More information about the Python-list
mailing list