#python #reflection
#python #отражение
Вопрос:
Как мне добавить __len__(...)
к существующему объекту len(...)
понравившимся способом?
Вариант использования заключается в запоминании длины генератора после его первой итерации таким образом, чтобы не требовалось писать / изменять код между сайтами итераций.
Вот что у меня есть до сих пор:
def generator2iterator(generator):
class Iterator(object):
def __iter__(self):
i = 0
for e in generator():
i = 1
yield e
#self.__len__ = types.MethodType(lambda self: i, self)
self.__len__ = (lambda self: i).__get__(self)
return Iterator()
def test_generator():
yield 3
iterator = generator2iterator(test_generator)
print(list(iterator))
# [3]
print(iterator.__len__())
# 1
print(len(iterator))
# TypeError: object of type 'Foo' has no len()
Ответ №1:
Определите атрибут, который содержит длину, и верните его для __len__
.
def generator2iterator(generator, length=None):
class Iterator(object):
def __iter__(self):
for i, e in enumerate(generator(), 1):
self._len = i
yield e
#self.__len__ = types.MethodType(lambda self: i, self)
def __len__(self):
if not hasattr(self, '_len'):
raise TypeError("object of type 'Iterator' has no defined len() yet.")
return self._len
return Iterator()
# examples:
## define a generator with 10 elements
def g():
for i in range(10):
yield i
# pass it to the iterator
it = generator2iterator(g)
# check len
len(it)
TypeError: object of type 'Iterator' has no defined len() yet.
# run the iterator
for _ in it:
pass
# check the length
len(it)
# returns:
10
Комментарии:
1. Тогда было бы время, для которого
len(it)
дается неправильный ответ.2. Вы не всегда можете заранее определить длину генератора. Можете ли вы привести пример ожидаемого результата?
3. Я бы хотел
__len__
, чтобы он не был определен (вызовыlen
завершаются ошибкой, как и должны быть) до первой итерации, после чего мы знаем длину генератора — поэтому (возможно) динамически добавляем метод.4. о! в этом случае удалите определение
__init__
и вызовите ошибку. смотрите мое обновление