Specialized @property decorators in python
<p>I have a few classes each of which has a number of attributes. What all of the attributes have in common is that they should be numeric properties. This seems to be an ideal place to use python's decorators, but I can't seem to wrap my mind around what the correct implementation would be. Here is a simple example:</p>

<pre><code>class Junk(object):
    def __init__(self, var):
        self._var = var

    @property
    def var(self):
        """A numeric variable"""
        return self._var

    @var.setter
    def size(self, value):
        # need to make sure var is an integer
        if not isinstance(value, int):
            raise ValueError("var must be an integer, var = {}".format(value))
        self._var = value

    @var.deleter
    def size(self):
        raise RuntimeError("You can't delete var")
</code></pre>

<p>It seems to me that it should be possible to write a decorator that does everything so that the above can be transformed into:</p>

<pre><code>def numeric_property(*args, **kwargs):
    ...

class Junk(object):
    def __init__(self, var):
        self._var = var

    @numeric_property
    def var(self):
        """A numeric variable"""
        return self._var
</code></pre>

<p>That way the new <code>numeric_property</code> decorator can be used in many classes.</p>

<h2>Option 1: inherit from <code>property</code></h2>

<p><code>property</code> is a descriptor. See <a href="https://docs.python.org/3/howto/descriptor.html" rel="nofollow">Descriptor HowTo on python.org</a>.</p>

<p>So, can inherit from <code>property</code> and override the relevant methods.</p>

<p>For example, to enforce int on setter:</p>

<pre><code>class numeric_property(property):
    def __set__(self, obj, value):
        assert isinstance(value, int), "numeric_property requires an int"
        super(numeric_property, self).__set__(obj, value)

class A(object):
    @numeric_property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value
</code></pre>

<p>And now you have integers enforced:</p>

<pre><code>&gt;&gt;&gt; a = A()
&gt;&gt;&gt; a.x = 'aaa'
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  File "&lt;stdin&gt;", line 3, in __set__
AssertionError: numeric_property requires an int
</code></pre>

<hr>

<h2>Option 2: Create a better descriptor</h2>

<p>On the other hand, it may be even better to implement a brand new descriptor which does not inherit from property, which would enable you to define the property in one go.</p>

<p>It would be nicer to have this kind of interface:</p>

<pre><code>class A(object):
    x = numeric_property('_x')
</code></pre>

<p>For that you would implement a descriptor which takes the attribute name:</p>

<pre><code>class numeric_property(object):
    def __init__(self, private_attribute_name, default=0):
        self.private_attribute_name = private_attribute_name
        self.default = default

    def __get__(self, obj, typ):
        if not obj: return self
        return getattr(obj, self.private_attribute_name, self.default)

    def __set__(self, obj, value):
        assert isinstance(value, int), "numeric_property requires an int"
        setattr(obj, self.private_attribute_name, value)
</code></pre>

<hr>

<p><strong>Disclaimer :)</strong></p>

<p>I would rather not enforce strict typing in Pyhon, because Python is much more powerful without it.</p>

python python-3.x decorator python-decorators