Python - insert static class-method-value in class attribute dictionary

Viewed 135

How can I do this (without init):

class Test(Objekt, UserMixin): 
  
    @staticmethod
    def Foo():
        return 1

    my_dict = {
        "foo_val": Test.Foo(),
    } 

I tried:

    my_dict = {
        "foo_val": lambda: Test.Foo(),
    } 

But of course the lamda function is stored, not its result!

(this example is simplified)

4 Answers

You have a few alternatives here:

call the function before decorating it with staticmethod:

class Test(Objekt, UserMixin): 
  
    def Foo():
        return 1

    my_dict = {
        "foo_val": Foo(),
    }

    Foo = staticmethod(Foo)

Or, add it to the dictionary outside the class statement:

class Test(Objekt, UserMixin): 

    my_dict = {}

    @staticmethod
    def Foo():
        return 1

Test.my_dict["foo_val"] = Test.Foo()

Finally, use the __func__ attribute of the staticmethod object:

class Test(Objekt, UserMixin): 
  
    @staticmethod
    def Foo():
        return 1

    my_dict = {
        "foo_val": Foo.__func__(),
    } 

Not sure which of these three approaches is the cleanest, to be frank.

You can declare my_dict as property

@property
def my_dict(self):
    return {"foo_val": Test.Foo()}

One way could be to declare my_dict as a class property (or a normal instance property, if that's okay for your use case, that would save you from using the classproperty class).

class classproperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(owner)()

class Test():

    @staticmethod
    def Foo():
        return 1

    @classproperty
    def my_dict(cls):
        return {
            "foo_val": cls.Foo(),
        }

print(Test.my_dict)

Output:

{'foo_val': 1}

Using a normal property:

class Test():

    @staticmethod
    def Foo():
        return 1

    @property
    def my_dict(cls):
        return {
            "foo_val": cls.Foo(),
        }

print(Test().my_dict) # notice that this requires to create an instance!

Another way could be to

  1. use a metaclass

  2. fill my_dict after the class definition

Thanks to all! Just for completion. Another solution could be:

class Test(Objekt, UserMixin): 
  
    @staticmethod
    def Foo():
        return Test.my_dict["foo_val"]

    my_dict = {
        "foo_val": 1,
    } 

As mentioned, this is a special case and the "foo_val" entry has to be item of that dict! Thus I think this is a valid solution here. Otherwise I wold prefer one og the other solutions mentioned in this thread

Related