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 мы не требуем, чтобы атрибуты имели определенные типы: вместо этого мы документируем ожидаемые типы и предполагаем, что любые фактические параметры соответствуют. Обратите внимание, что это может означать совершенно не связанный тип, который реализует тот же метод: например, мы могли бы ожидать, что параметр является итеративным, без особого требования, чтобы он наследовал от списка или кортежа.

Другие вопросы по тегам