Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Static class method properties in Python

As the title says, I’m trying to give set/get functionality to my static classes in python. Basically, for a given static class with static attribute _x, I want to define a static property x that gives custom get and set function wrappers for _x.

Strangely it seems like the official Python docs say this functionality should exist. The docs say that as of version 3.9, you can use the @classmethod decorator to wrap property methods. However, it seems that this only works for getters, and not setters. For example, when I try to define a static property using this method, I get the following error:

class Foo:
  _x = 0

  @classmethod
  @property
  def x(self):
    return self._x

  @classmethod
  @x.setter
  def x(self, n):
    self._x = n

AttributeError: 'classmethod' object has no attribute 'setter'

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

If I flip the order, like:

class Foo:
  _x = 0

  @property
  @classmethod
  def x(self):
    return self._x

  @x.setter
  @classmethod
  def x(self, n):
    self._x = n

Then Foo.x returns a property object instead of calling the property’s fget function.

So it seems this approach is not going to work. I then tried to exploit the way that function decorators work, by redefining Foo:

class Foo:
  _x = 0

  def __get_x(self):
    return self._x

  def __set_x(self, n):
    self._x = n

  x = classmethod(property(fget=__get_x, fset=__set_x))

But no luck. Whenever I try to set Foo.x, i.e. with Foo.x = 2, it does not call the property setter but instead directly overwrites x entirely.

One solution I’ve seen bounced around is using python metaclasses to implement this functionality. While that could fix the issue, it isn’t ideal because A. I have many different static classes in my project and B. I use Sphinx to generate documentation for my code and it doesn’t always play nice with metaclasses.

I’ve been looking for a solution to this issue for a while and I’m not sure what the best "pythonic" fix for it is. If metaclasses are the "cleanest" solution, how can I implement them in such a way that I don’t have to write a lot of redundant code? Maybe I could write a custom function decorator that enables class property-esque functionality? Any help would be appreciated.

>Solution :

An instance’s properties must be defined on its class. If the instance in question is itself a class, its properties must still be defined on its class: that is to say, since the instance is a class (which is usually an instance of type), the properties must be defined on the class’s metaclass.

class Meta(type):

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, n):
        self._x = n

class Foo(metaclass=Meta):
    _x = 0

Despite the drawbacks of using metaclasses, this is the way that works.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading