24

I want to assign a function implementation dynamically.

Let's start with the following:

class Doer(object):

    def __init__(self):
        self.name = "Bob"

    def doSomething(self):
        print "%s got it done" % self.name

def doItBetter(self):
    print "Done better"

In other languages we would make doItBetter an anonymous function and assign it to the object. But no support for anonymous functions in Python. Instead, we'll try making a callable class instance, and assign that to the class:

class Doer(object):

    def __init__(self):
        self.name = "Bob"

class DoItBetter(object):

    def __call__(self):
        print "%s got it done better" % self.name

Doer.doSomething = DoItBetter()
doer = Doer()
doer.doSomething()

That gives me this:

Traceback (most recent call last): Line 13, in doer.doSomething() Line 9, in call print "%s got it done better" % self.name AttributeError: 'DoItBetter' object has no attribute 'name'

Finally, I tried assigning the callable to the object instance as an attribute and calling it:

class Doer(object):

    def __init__(self):
        self.name = "Bob"

class DoItBetter(object):

    def __call__(self):
        print "%s got it done better" % self.name


doer = Doer()
doer.doSomething = DoItBetter()
doer.doSomething()

This DOES work as long as I don't reference self in DoItBetter, but when I do it gives me an name error on self.name because it's referencing the callable's self, not the owning class self.

So I'm looking for a pythonic way to assign an anonymous function to a class function or instance method, where the method call can reference the object's self.

4
  • Nothing wrong with the very first approach that you rejected. Why are you making it so complex? Commented Apr 29, 2012 at 18:00
  • 2
    Your error is really odd - are you trying to run a Python script with a ruby interpreter? (Your file is called prog.rb, .py is the Python file extension). The error definitely isn't from Python - self isn't a keyword in Python. Commented Apr 29, 2012 at 18:02
  • My mistake- ran it on an online codepad with ruby settings- fixed Commented Apr 29, 2012 at 18:19
  • 1
    @David- you're right- I was making it way too complicated Commented Apr 29, 2012 at 18:20

2 Answers 2

41

yak's answer works great if you want to change something for every instance of a class.

If you want to change the method only for a particular instance of the object, and not for the entire class, you'd need to use the MethodType type constructor to create a bound method:

from types import MethodType

doer.doSomething = MethodType(doItBetter, doer)
Sign up to request clarification or add additional context in comments.

2 Comments

At least in Python 3, it should be doer.doSomething = MethodType(doItBetter, doer) . A good explanation of the different cases for methods and functions is given in stackoverflow.com/questions/972/…
@yanlend this question was asked for Python 2.
40

Your first approach was OK, you just have to assign the function to the class:

class Doer(object):
    def __init__(self):
        self.name = "Bob"

    def doSomething(self):
        print "%s got it done" % self.name

def doItBetter(self):
    print "%s got it done better" % self.name

Doer.doSomething = doItBetter

Anonymous functions have nothing to do with this (by the way, Python supports simple anonymous functions consisting of single expressions, see lambda).

1 Comment

+1 being anonymous doesn't matter here - all that matters is you can assign a function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.