Существует много способов добиться чего-то подобного. Если муфта формат ввода в объектной модели является приемлемым, то вы можете использовать дескрипторы для создания адаптеров типа:
class TypeAdaptingProperty(object):
def __init__(self, key, type_, factory=None):
self.key = key
self.type_ = type_
if factory is None:
self.factory = type_
def __get__(self, instance, owner):
if instance is None:
return self
return getattr(instance, self.key)
def __set__(self, instance, value):
if not isinstance(value, self.type_):
value = self.factory(value)
setattr(instance, self.key, value)
def __delete__(self, instance):
delattr(instance, self.key)
class Book(object):
isbn = TypeAdaptingProperty('isbn_', ISBNNumber)
b = Book()
b.isbn = 123 # Does the equivalent of b.isbn = ISBNNumber(123)
Однако, если вы не полностью контролировать структуру сообщения, такой связи не является хорошей идеей. В таких случаях мне нравится использовать шаблон интерпретатора для адаптации входных сообщений к типам вывода. Я создаю небольшую структуру, которая позволяет мне создавать декларативные структуры объектов для обработки входных данных.
Каркас может выглядеть примерно так:
class Adaptor(object):
"""Any callable can be an adaptor. This base class just proxies calls
to an appropriately named method."""
def __call__(self, input):
return self.adapt(input)
class ObjectAdaptor(Adaptor):
"""Adaptor to create objects adapting the input value to the
factory function/constructor arguments, and optionally setting
fields after construction."""
def __init__(self, factory, args=(), kwargs={}, fields={}):
self.factory = factory
self.arg_adaptors = args
self.kwarg_adaptors = kwargs
self.field_adaptors = fields
def adapt(self, input):
args = (adaptor(input) for adaptor in self.arg_adaptors)
kwargs = dict((key, adaptor(input)) for key,adaptor in self.kwarg_adaptors.items())
obj = self.factory(*args, **kwargs)
for key, adaptor in self.field_adaptors.items():
setattr(obj, key, adaptor(input))
return obj
def TypeWrapper(type_):
"""Converts the input to the specified type."""
return ObjectAdaptor(type_, args=[lambda input:input])
class ListAdaptor(Adaptor):
"""Converts a list of objects to a single type."""
def __init__(self, item_adaptor):
self.item_adaptor = item_adaptor
def adapt(self, input):
return map(self.item_adaptor, input)
class Pick(Adaptor):
"""Picks a key from an input dictionary."""
def __init__(self, key, inner_adaptor):
self.key = key
self.inner_adaptor = inner_adaptor
def adapt(self, input):
return self.inner_adaptor(input[self.key])
Переходники сообщение выглядеть примерно так:
book_message_adaptor = ObjectAdaptor(Book, kwargs={
'isbn': Pick('isbn_number', TypeWrapper(ISBNNumber)),
'authors': Pick('authorlist', ListAdaptor(TypeWrapper(Author)))
})
Обратите внимание, что названия структуры сообщения не может быть такой же, как модель объекта. Сам
обработки сообщений выглядит следующим образом:
message = {'isbn_number': 123, 'authorlist': ['foo', 'bar', 'baz']}
book = book_message_adaptor(message)
# Does the equivalent of:
# Book(isbn=ISBNNumber(message['isbn_number']),
# authors=map(Author, message['author_list']))
Включает ли это хлопание кого-либо с рыбой? – amelvin
Не подходит ли рассол для этого - даже если бы его исходный код не ввел бы тип информации – Mark
Моя проблема заключается в чтении, а не в написании и чтении (текстовом) формате сериализации, который я не контролирую (который не включает информацию о типе). Pickle (я полагаю) хранит всю информацию о типе, которую ему нужно рассыпать (имена модулей и классов). – Tikitu