Python - function as class attribute becomes a bound method

Python is not a message based OO system1. Instead, similar to JavaScript, properties are resolved to first-class functions and then invoked; the behavior differs a bit in the mechanics of such, as discovered.

In Python the requirement is that methods have at least one parameter, normally called self, that will be automatically supplied the associated instance when it is invoked as a method.

Furthermore (and perhaps to the point of the question), Python does not differentiate between using def f.. or f = some_func() when establishing instance member bindings; arguably this matches behavior outside of classes.

In the example, assigning the function to the instance 'makes it expect to be treated like an instance method'. It is the exact same - parameterless - function called in both cases; only the future usage of such is relevant.

Now, unlike JavaScript, Python handles methods and object association through the concept of bound methods - functions resolved as methods are always 'bound'.

The behavior of a.f returning a bound method - function that will automatically supply the bound object to the first parameter as self - is done independently of the source of the function. In this case that means the parameterless function cannot be used when it is 'bound' as it does not accept a self parameter.

As a demonstration, the following will fail in the same way because the source underlying method does not meet the minimum requirements of accepting the instance as an argument:

g = a.f
g()

In this case calling g() is equivalent to calling func(a).


1 For comparison, Java, C#, Ruby, and SmallTalk are message based OO systems - in these an object is told to invoke a method by a 'name', instead of resolving a method (or function) as a value which can be invoked.


You assigned a function to the attribute A.f (the attribute f of the class A). The attribute A.f was defined as part of the class. It is a function, so it is by default an instance method of that class.

Creating an instance (named a) of class A causes that instance to have an attribute f, and you access that by the name a.f. This is a bound method (cause it's bounded to the object a; further explanation here).

Every instance method, when it is called, automatically receives the instance as its first argument (conventionally named self). Other types of method are possible: - see class methods and static methods.

For this reason the error says that func takes no arguments (as it's defined as def func():) but received 1 (self).

To do what you want, you should tell python that you're using a static method

def func():
    pass

class A(object):
    f = staticmethod(func)