Python: efficient way to ensure attribute types within an object?
<p>What's the most efficient way (where "efficient" doesn't necessarily mean <em>fast</em>, but <em>"elegant"</em>, or <em>"maintainable"</em>) to do type check when setting attributes in an object?</p>

<p>I can use <code>__slots__</code> to define the allowed attributes, but how should I constrain the types?</p>

<p>Surely I can write <em>"setter"</em> methods for each attribute, but I find it a bit cumbersome to maintain since my type checks are usually simple.</p>

<p>So I'm doing something like this:</p>

<pre><code>import datetime

# ------------------------------------------------------------------------------
# MyCustomObject
# ------------------------------------------------------------------------------
class MyCustomObject(object):
    pass

# ------------------------------------------------------------------------------
# MyTypedObject
# ------------------------------------------------------------------------------
class MyTypedObject(object):     
    attr_types = {'id'         : int,
                  'start_time' : datetime.time,
                  'duration'   : float,
                  'reference'  : MyCustomObject,
                  'result'     : bool,
                  'details'    : str}

    __slots__ = attr_types.keys()

    # --------------------------------------------------------------------------
    # __setattr__
    # --------------------------------------------------------------------------
    def __setattr__(self, name, value):
        if name not in self.__slots__:
            raise AttributeError(
                "'%s' object has no attribute '%s'" 
                % (self.__class__.__name__, name))
        if type(value) is not self.attr_types[name]:
                raise TypeError(
                    "'%s' object attribute '%s' must be of type '%s'" 
                    % (self.__class__.__name__, name, 
                       self.attr_types[name].__name__))
        # call __setattr__ on parent class
        super(MyTypedObject, self).__setattr__(name, value)
</code></pre>

<p>Which works fine for my purpose:</p>

<pre><code>&gt;&gt;&gt; my_typed_object            = MyTypedObject()
&gt;&gt;&gt; my_typed_object.id         = "XYZ"
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  File "&lt;stdin&gt;", line 28, in __setattr__
TypeError: 'MyTypedObject' object attribute 'id' must be of type 'int'
&gt;&gt;&gt; my_typed_object.id         = 123
&gt;&gt;&gt; my_typed_object.reference  = []
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  File "&lt;stdin&gt;", line 28, in __setattr__
TypeError: 'MyTypedObject' object attribute 'reference' must be of type 'MyCustomObject'
&gt;&gt;&gt; my_typed_object.reference  = MyCustomObject()
&gt;&gt;&gt; my_typed_object.start_time = "13:45"
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  File "&lt;stdin&gt;", line 28, in __setattr__
TypeError: 'MyTypedObject' object attribute 'start_time' must be of type 'time'
&gt;&gt;&gt; my_typed_object.start_time = datetime.time(13, 45)
</code></pre>

<p>Is there a better way to do this? Having worked with Python for a while now, I feel like I'm reinventing the wheel.</p>
