Home > OS >  Correct way to use properties
Correct way to use properties

Time:10-18

My property getter/setters before

class Child(Base):
    @property
    def prop(self) -> Optional[int]:
        """Doc"""
        return getattr(self, "_prop", None)

    @prop.setter
    def prop(self, value: int):
        self._set("prop", value)   # where _set itself is a method to reduce boilerplate

Now,

prop = Prop.int_prop("prop", "Doc")

where Prop.int_prop looks like this:

@staticmethod
def int_prop(name: str, doc: str) -> property:
    def fget(self: Base) -> Optional[int]:
        return getattr(self, "_"   name, None)
    
    def fset(self: Base, value: int) -> None:
        self._set(name, value)
    
    return property(fget, fset, doc=doc)

EDIT: _set method

# Dump value to event store if event exists
event = self._events.get(name)
if event:
   logger.info(f"Dumping value {value} to {repr(event)}")
   event.dump(value)

# Assign value to local variable
setattr(self, "_"   name, value)

On one hand this makes me feel proud, because close to 70% of the project I am working on is the property getters/setters. While I agree the above method is more Pythonic and clean, the method below reduces a lot of code. However, it takes away the ability of VS Code to show docstrings below property names.

Is there a solution to this or a better method in general?

CodePudding user response:

Unless VS Code supports PEP-257's definition of attribute docstrings, this can only be considered an extended comment rather than a proper answer. I have never used VS Code and cannot test its support for this.

In its defense, it supplies the docstring syntactically, rather than setting the __doc__ attribute dynamically at runtime, so there's a chance it will resolve the main issue raised in the question.


If I weren't concerned with IDE support, I would write a custom descriptor and follow PEP-257 guidelines for attribute docstrings.

# Adapted from examples in https://docs.python.org/3/howto/descriptor.html
class IntPropety:
    def __set_name__(self, owner, name):
        self.public_name = name
        self.private_name = "_"   name

    def __get__(self, obj, objtype=None) -> Optional[int]:
        if obj is None:
            return self
        return getattr(obj, self.private_name)

    def __set__(self, obj, value):
        event = obj._events.get(self.public_name)
        if event:
            logger.info(f"Dumping value {value} to {repr(event)}")
            event.dump(value)

        setattr(obj, self.private_name, value)

    

class Child(Base):
    prop = IntProperty()
    """Doc"""
  • Related