В python 3.x я пытаюсь реализовать класс, который будет прокси для последовательности, заданной в качестве параметра. Прокси также принимает функцию, которая вызывается для каждого элемента входной последовательности.
Каким будет правильный способ для прокси-класса реализовать методы __getitem__
, __iter__
и __len__
динамически в зависимости от их доступности во входной последовательности. Вот моя попытка сделать это (я называю свои последовательности «поставщиками», а функция - «преобразованием»):
class TransformProviderProxy:
def __init__(self, input_provider, transform):
self.input_provider = input_provider
self.transform = transform
def __iter__(self):
# Use generator expressions to produce a new iterator when requested
return (self.transform(data_sample) for data_sample in self.input_provider)
def __getattr__(self, name):
if name == "__getitem__" and hasattr(self.input_provider, "__getitem__"):
return self._getitem_impl
elif name == "__len__" and hasattr(self.input_provider, "__len__"):
return self._len_impl
else:
return None
def _getitem_impl(self, index):
return self.transform(self.input_provider[index])
def _len_impl(self):
return len(self.input_provider)
Однако это не удается, потому что кажется, что python обходит __getattr__
при поиске __getitem__
. Как правильно это сделать?
В качестве бонуса, есть ли способ сделать это, когда мой прокси-класс динамически наследует от collections.abc.Sequence
или collections.abc.Iterable
в зависимости от входной последовательности?
PS: Я также думал о том, чтобы просто реализовать __getitem__
в любом случае и полагаться на перехват TypeError при попытке вызвать его в неиндексируемой входной последовательности, но я хотел бы иметь возможность проверить, индексируется ли мой прокси-класс, ища наличие __getitem__
без явного вызова его с индексом.
1 ответ
Просто внедрите __getitem__
и __len__
. Он завершится ошибкой с соответствующим сообщением об ошибке, если input_provider
не реализует следующие операции:
class TransformProviderProxy:
def __init__(self, input_provider, transform):
self.input_provider = input_provider
self.transform = transform
def __iter__(self):
# Use generator expressions to produce a new iterator when requested
return (self.transform(data_sample) for data_sample in self.input_provider)
def __getitem__(self, index):
return self.transform(self.input_provider[index])
def __len__(self):
return len(self.input_provider)
Как пример:
>>> t = TransformProviderProxy(2, lambda x: x+2)
>>> t[1]
TypeError: 'int' object is not subscriptable
>>> t = TransformProviderProxy([1,2,3,4], lambda x: x+2)
>>> t[1]
4
Похожие вопросы
Новые вопросы
python
Python - это многопарадигмальный, динамически типизированный, многоцелевой язык программирования. Он разработан для быстрого изучения, понимания и использования, а также для обеспечения чистого и единообразного синтаксиса. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Тем не менее, для вопросов о Python, связанных с версией, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas и NumPy) включите его в теги.
collections.abc.Sequence
), не пытаясь явно его проиндексировать. Может, мне просто следует признать, что твой путь более питонический?wrapt
а этоObjectProxy
. Это может содержать какое-то (уже построенное) решение вашей непосредственной проблемы. Извините, я не видел ваш последний абзац раньше ... :(