5

I get an error when trying to bind a class method to a function. Why?

def foo():
    print "Hello world"

class something(object):
    bar = foo

test = something()
test.bar()

TypeError: foo() takes no arguments (1 given)

Also, if I am unable to modify foo, can I do this adaptation from within the class definition?

6 Answers 6

11

A simple way to do it is to wrap the function in a staticmethod inside A:

class A():
    bar = staticmethod(foo)

>>> test = A()
>>> test.bar()
Hello world
Sign up to request clarification or add additional context in comments.

1 Comment

I like this solution, a lot. I guess this only works if I don't need to access the instance from within the function (but that was part of the assumption in my update)
6

A class method in python always takes at least one argument, usually called self. This example is taken from the official Python tutorial:

# Function defined outside the class
def f1(self, x, y):
    return min(x, x+y)

class C:
    f = f1
    def g(self):
        return 'hello world'
    h = g

Note that both methods, regardless of whether they are defined outside or inside of the class, take self as an argument.

Edit: If you really can't change your foo function, then you can do something like this:

>>> def foo():
...     print "Hello World"
...
>>> class something(object):
...     def bar(self): foo()
...
>>> test = something()
>>> test.bar()
Hello World

4 Comments

Say I can't modify foo (or that I would prefer to not change it's signature). Can I do this adaptation from within the class definition?
Fantastic. Thanks @srgerg. I love Python.
See @BrenBarn for an interesting way of solving the "unable to change foo" problem
Yes I like BrenBarn's solution better.
1

When you call a class method this way you pass the class instance as the first parameter. When you call test.bar what in fact happens is more like bar(test). You pass an argument to the method.

Comments

1

Class methods all have a first argument of the instance of the class. So add a parameter to your function and it would work.

Comments

1

The initial def creates a function object named foo. Since it's outside any class, it's just a function that takes no arguments. The assignment bar = foo just gives the new name test.bar to that same function object. The call test.bar(), however, assumes that bar is a class method, and passes the object test as the first argument to the method (the one that you would normally call self). You could call it as a static method with something.bar() and not get the error.

Comments

1

Remember that when a python class calls one of it's methods it will pass in a self argument. You need to account for that in your code:

def foo(self):
    print ("Hello world")

class something(object):
    bar = foo

test = something()
test.bar()

You can read all about classes in the Python Documentation

The easiest workaround to not passing in a self that I can think of is:

def foo():
    print ("Hello world")

class something(object):
    bar = [foo] # contains pointer to static method

test = something()
test.bar[0]() # calls the static method

2 Comments

Thanks. I have updated the OP to clarify that I am looking for a way of doing this that does not require modifying foo, but only the class definition itself.
@user815423426 Edited, There may be a better way but this one works, and i suppose you can add as many different functions as you want now.

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.