Python: эффективный способ обеспечения типов атрибутов внутри объекта?
Какой самый эффективный способ (где "эффективный" не обязательно означает быстрый, но "элегантный" или "поддерживаемый") для проверки типов при установке атрибутов в объекте?
я могу использовать __slots__
определить разрешенные атрибуты, но как мне ограничить типы?
Конечно, я могу написать "установочные" методы для каждого атрибута, но я нахожу это немного громоздким, поскольку мои проверки типов обычно просты.
Итак, я делаю что-то вроде этого:
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)
Который отлично работает для моей цели:
>>> 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)
Есть лучший способ сделать это? Проработав некоторое время с Python, я чувствую, что заново изобретаю колесо.
2 ответа
Библиотека, которая уже реализует то, что вы ищете (и предоставляет множество других функций) - это Enthought Traits.
Вы должны спросить себя, почему вы чувствуете необходимость сделать это. Это, конечно, не очень Pythonic. Обычно в Python мы не требуем, чтобы атрибуты имели определенные типы: вместо этого мы документируем ожидаемые типы и предполагаем, что любые фактические параметры соответствуют. Обратите внимание, что это может означать совершенно не связанный тип, который реализует тот же метод: например, мы могли бы ожидать, что параметр является итеративным, без особого требования, чтобы он наследовал от списка или кортежа.