3

Let's assume I have a class, with a static method, and I want a class property to be set to the value that this method returns:

class A:
    @staticmethod
    def foo():
        return 12

     baz = foo()

But doing this I get an error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in A
TypeError: 'staticmethod' object is not callable

I found a way to get around this:

class A:
    class B:
        @staticmethod
        def foo():
            return 2
baz = B.foo()

But for example if I write:

class A:
    class B:
        @staticmethod
        def foo():
            return 2

    class C:
        baz = B.foo()

I also get an error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in A
  File "<stdin>", line 7, in C
NameError: name 'B' is not defined

Is there a way to call static methods from within a class while declaring it? Why 1st and 3rd examples of code does not work but 2nd does? How python interpretor handles such declarations?

martineau
  • 119,623
  • 25
  • 170
  • 301
arrowknee
  • 63
  • 3
  • 7

2 Answers2

5

The staticmethod is a descriptor. A descriptor exposes the __get__(instance, cls) method allowing it to be accessed either through an instance or at the class level.

Now in your case you wish to call it within a class stanza. Normally this would not be possible as neither an instance nor the class are yet available. However a staticmethod ignores both in any case so you can use the following rather nasty approach to call it.

class A:
    @staticmethod
    def foo():
        return 12

    baz = foo.__get__(None, object)()

Then

>>> A.baz
12

Note: The only reason to pass object as the second argument is that staticmethod insists on being passed a class of some kind as the second argument.

donkopotamus
  • 22,114
  • 2
  • 48
  • 60
1

This is also a workaround, but it might help.

In the class body you cannot refer to the class being created. OTOH a class decorator receives an initialized class, thus it can call its methods directly.

def add_baz(cls):
    cls.baz = cls.foo()
    return cls 

@add_baz
class A:
    @staticmethod
    def foo():
        return 12
VPfB
  • 14,927
  • 6
  • 41
  • 75