pythonic use of properties?

Michael Spencer mahs at telcopartners.com
Fri Apr 15 00:17:54 EDT 2005


Marcus Goldfish wrote:
> I'd like advice/opinions on when it is appropriate to do

Just an opinion...
> attribute/property validation in python.  I'm coming from a C#/Java
> background, where of course tons of "wasted" code is devoted to
> property validation.  Here is a toy example illustrating my question:
> 
> #   Example: mixing instance attributes with properties.  Is it pythonic to
> #   validate property data in setters?  Since tens and ones are never
> #   validated, the class can be "broken" by setting these directly
> class SillyDecimal(object):
>    """A silly class to represent an integer from 0 - 99."""
>    def __init__(self, arg=17):
>        if isinstance(arg, tuple):
>            self.tens = arg[0]
>            self.ones = arg[1]
>        else:
>            self.number = arg
> 
>    def getNumber(self):
>        return self.tens*10 + self.ones
>    def setNumber(self, value):
>        if value < 0 or value > 99:
>            raise ArgumentException("Must in [0, 99]")
>        self.tens = value // 10
>        self.ones = value % 10
>    number = property(getNumber, setNumber, None, "Complete number, [0-99]")

It is conventional to indicate 'private' attributes with the _ prefix.
By this standard, you have three 'public' interfaces: number, get/setNumber and 
ones/tens, which is confusing and error-prone.  Moreover, if you are going to 
validate number, it might make more sense to put all the validation logic into 
the setter vs. splitting some into __init__.  So your class could look like:

class SillyDecimal1(object):
     """A silly class to represent an integer from 0 - 99."""
     def __init__(self, value = 17):
         self.number = value
     def _getNumber(self):
        return self._tens*10 + self._ones
     def _setNumber(self, value):
         if isinstance(value, tuple):
             value  = value[0] * 10 + value[1]
         if value in range(100):
             self._tens = value /10
             self._ones = value % 10
         else:
             raise ValueError, "Number out of range(100)"
     number = property(_getNumber, _setNumber, None, "Complete number, [0-99]"

There is nothing to stop a user from setting _tens and _ones directly, but their 
names indicate that this should not be done.

As for whether it is appropriate to validate the value at all, I think that 
depends on your larger design.

Note that one of the main purposes of properties is retrofitting bare attributes 
with getters/setters.  So, an initial version of  your class might be:

class SillyDecimal0(object):
     """A silly class to represent an integer from 0 - 99."""
     def __init__(self, value = 17):
         self.number = value

Later you can add the getter/setter/property logic if it turns out to be 
necessary, without changing the interface (except for the addition of a couple 
of 'private' attributes and 'private' methods, which well-behaved callers should 
not touch anyway.


Michael




More information about the Python-list mailing list