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