mkasfeldt
mkasfeldt

Reputation: 33

Is there a faster way to use @property for multiple properties in a class?

Is there a shorter way to add properties to a class and have validation for setting than using the @property method? The below code is a sample. I would like to be able to many properties in a class that will be validated and doing it this way seems redundant. Any advice is greatly appreciated!

def valid_max(max_val=10):
"""
Decorator to check for valid value of a number between min and max

"""
def valid_value_decorator(func):
    def func_wrapper(wraps,value):
        if value <= max_val:
            return func(wraps,value)
        else:
            raise(Exception('Value above max'))
    return func_wrapper
return valid_value_decorator

class Test(object):
    def __init__(self):
        self._x=0
        self._y=0

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

    @x.setter
    @valid_max(max_val=10)
    def x(self,data):
       self._x = data

    @property
    def y(self):
        return self._y

    @y.setter
    @valid_max(max_val=10)
    def y(self,data):
        self._y = data

Upvotes: 1

Views: 759

Answers (1)

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 251196

You can write a factory function to produce the properties:

def CustomProp(name, maxval):
    name = '_' + name

    @property
    def pro(self):
        return getattr(self, name)

    @pro.setter
    def pro(self, val):
        if not isinstance(val, (int, float)):
            # In Python 2 -> '' > 10(or any number) is True, so better check the type as well.
            raise TypeError('Only integers and floats are allowed.')
        if val > maxval:
            raise ValueError("Value {!r} above maximum {!r}.".format(val, maxval))
        else:
            setattr(self, name, val)

    return pro

class Test(object):
    x = CustomProp('x', 10)
    y = CustomProp('y', 20)
    z = CustomProp('z', 30)

    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

Demo:

>>> t = Test(1, 2, 3)
>>> t.x = 10
>>> t.y = 11
>>> t.x = 11

Traceback (most recent call last):
  File "<pyshell#41>", line 1, in <module>
    t.x = 11
  File "/home/ashwini/py/so.py", line 14, in pro
    raise ValueError("Value {!r} above maximum {!r}.".format(val, maxval))
ValueError: Value 11 above maximum 10.
>>> t.x = 'Python'

Traceback (most recent call last):
  File "<pyshell#42>", line 1, in <module>
    t.x = 'Python'
  File "/home/ashwini/py/so.py", line 12, in pro
    raise TypeError('Only integers and floats are allowed.')
TypeError: Only integers and floats are allowed.
>>> t.z = 31

Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
    t.z = 31
  File "/home/ashwini/py/so.py", line 14, in pro
    raise ValueError("Value {!r} above maximum {!r}.".format(val, maxval))
ValueError: Value 31 above maximum 30.
>>> t.x, t.y, t.z
(10, 11, 3)

Upvotes: 2

Related Questions