Search code examples
pythonclassstaticdecorator

Python: Regular method and static method with same name


Introduction

I have a Python class, which contains a number of methods. I want one of those methods to have a static counterpart—that is, a static method with the same name—which can handle more arguments. After some searching, I have found that I can use the @staticmethod decorator to create a static method.

Problem

For convenience, I have created a reduced test case which reproduces the issue:

class myclass:

    @staticmethod
    def foo():
        return 'static method'

    def foo(self):
        return 'public method'

obj = myclass()
print(obj.foo())
print(myclass.foo())

I expect that the code above will print the following:

public method
static method

However, the code prints the following:

public method
Traceback (most recent call last):
  File "sandbox.py", line 14, in <module>
    print(myclass.foo())
TypeError: foo() missing 1 required positional argument: 'self'

From this, I can only assume that calling myclass.foo() tries to call its non-static counterpart with no arguments (which won't work because non-static methods always accept the argument self). This behavior baffles me, because I expect any call to the static method to actually call the static method.

I've tested the issue in both Python 2.7 and 3.3, only to receive the same error.

Questions

Why does this happen, and what can I do to fix my code so it prints:

public method
static method

as I would expect?


Solution

  • A similar question is here: override methods with same name in python programming

    functions are looked up by name, so you are just redefining foo with an instance method. There is no such thing as an overloaded function in Python. You either write a new function with a separate name, or you provide the arguments in such a way that it can handle the logic for both.

    In other words, you can't have a static version and an instance version of the same name. If you look at its vars you'll see one foo.

    In [1]: class Test:
       ...:     @staticmethod
       ...:     def foo():
       ...:         print 'static'
       ...:     def foo(self):
       ...:         print 'instance'
       ...:         
    
    In [2]: t = Test()
    
    In [3]: t.foo()
    instance
    
    In [6]: vars(Test)
    Out[6]: {'__doc__': None, '__module__': '__main__', 'foo': <function __main__.foo>}