Monkeypatching an object to become callable

7stud bbxx789_05ss at yahoo.com
Sun Aug 9 20:55:26 EDT 2009


On Aug 9, 1:02 pm, Nikolaus Rath <Nikol... at rath.org> wrote:
> Hi,
>
> I want to monkeypatch an object so that it becomes callable, although
> originally it is not meant to be. (Yes, I think I do have a good reason
> to do so).
>
> But simply adding a __call__ attribute to the object apparently isn't
> enough, and I do not want to touch the class object (since it would
> modify all the instances):
>
> >>> class foo(object):
>
> ...   pass
> ...>>> t = foo()
> >>> def test():
>
> ...   print 'bar'
> ...>>> t()
>
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> TypeError: 'foo' object is not callable>>> t.__call__ = test
> >>> t()
>
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> TypeError: 'foo' object is not callable>>> t.__call__()
>
> bar
>
> Is there an additional trick to get it to work?
>
> Best,
>
>    -Nikolaus
>
> --
>  »Time flies like an arrow, fruit flies like a Banana.«
>
>   PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6  02CF A9AD B7F8 AE4E 425C


With an old-style class your code will work:

class A:
    pass

def test():
    print "test"

a = A()
a.__call__ = test

a()

--output:--
test


a2 = A()
a2()

--output:--

    a2()
AttributeError: A instance has no __call__ method



Another option is to use the *decorator pattern*.  The decorator
pattern can be used when you want to add additional methods and
attributes to an object, and you don't want to disturb the original
class:

class A(object):
    def __init__(self, x):
        self.x = x

    def sayhi(self):
        print "hi"


class Wrapper(object):
    def __init__(self, obj, func):
        self.obj = obj
        self.func = func

    def __call__(self, *args):
        return self.func(*args)

    def __getattr__(self, name):
        return object.__getattribute__(self.obj, name)


def test():
    print "test"

a = A(10)
w = Wrapper(a, test)
w()
print w.x
w.sayhi()

--output:--
test
10
hi




More information about the Python-list mailing list