Reputation: 6661
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.
Upvotes: 2
Views: 373
Reputation: 39990
A library that already implements what you're looking for (and provides a bunch of other features) is Enthought Traits.
Upvotes: 1
Reputation: 600059
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.
Upvotes: 1