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

I can use `__slots__` to define the allowed attributes, but how should I
constrain the types?

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

So I'm doing something like this:

    
    
    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)
    

Which works fine for my purpose:

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

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


Answer: You should ask yourself why you feel the need to do this. It's certainly not
very Pythonic. Normally in Python we don't demand that attributes have
specific types: instead, we document the expected types, and assume that any
actual parameters conform. Note that this can mean a completely unrelated type
that implements the same method: for example, we might expect that a parameter
is iterable, without specifically demanding that it inherits from list or
tuple.

