简体   繁体   中英

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'

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 , ie 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.

An instance's properties must be defined on its class. To define properties on a class, the rule still holds: when considering the class as an instance, its properties must be defined on the class's class (its 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM