#python #inheritance #overriding #iterable
#python #наследование #переопределение #повторяемый
Вопрос:
Я хочу переопределить __iter__
метод ExternalIter
, который определен во внешней библиотеке, поэтому я не могу изменить исходный код ExternalIter
класса. Я реализовал два разных способа переопределения в MyIter2
и MyIter3
.
class ExternalIter:
def __init__(self):
self.x = iter([
(1, 2),
(3, 4),
(5, 6),
(7, 8),
(9, 10)
])
def __iter__(self):
return self
def __next__(self):
return next(self.x)
class MyIter2(ExternalIter):
def __iter__(self):
while True:
try:
i, j = super().__next__()
yield i
yield j
except StopIteration:
break
class MyIter3(ExternalIter):
def __iter__(self):
for i, j in super().__iter__():
yield i
yield j
Первоначальное поведение ExternalIter
заключается в следующем:
for i in ExternalIter():
print(i)
# (1, 2)
# (3, 4)
# (5, 6)
# (7, 8)
# (9, 10)
Я хочу переопределить поведение __iter__
, как в следующем примере:
for i in MyIter2():
print(i)
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
# 10
MyIter2
работает как исключенный. Однако альтернативный способ переопределения, как я сделал в MyIter3
throws RecursionError
.
for i in MyIter3():
print(i)
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
<ipython-input-8-4e1114201cac> in <module>
----> 1 for i in MyIter3():
2 print(i)
<ipython-input-5-82da3324a8a3> in __iter__(self)
30
31 def __iter__(self):
---> 32 for i, j in super().__iter__():
33 yield i
34 yield j
... last 1 frames repeated, from the frame below ...
<ipython-input-5-82da3324a8a3> in __iter__(self)
30
31 def __iter__(self):
---> 32 for i, j in super().__iter__():
33 yield i
34 yield j
RecursionError: maximum recursion depth exceeded while calling a Python object
Можете ли вы объяснить, почему вторая реализация переопределения выдает ошибку, в то время как первый способ работает? Как я могу переопределить __iter__
использование super().__iter__()
без получения RecursionError
?
Можете ли вы объяснить, как __iter__
работает в этом контексте наследования, чтобы понять, почему super().__iter__()
ссылается на self
, а не на родительский?
Комментарии:
1. Я действительно пытался ответить на ваш вопрос, но это трудно объяснить. Я рекомендую вам помещать операторы print в начале ваших функций, например,
print("ExternalIter.__iter__")
,print("MyIter3.__iter__")
чтобы увидеть, что происходит. И чтобы решить вашу проблему, просто вернитеself.x
inExternalIter.__iter__
вместо justself
, и все готово. Хороший вопрос, жаль, что у меня недостаточно английского, чтобы дать ответ: D2. @Asocia У меня нет доступа к self.x . В реальном случае я могу выполнить итерацию только родительского элемента. Родительский элемент выполняет итерацию значений в результате сложных внутренних вычислений.
3. Обратите внимание, что
ExternalIter
вероятно, это не то, что вы думаете. Каждый итератор просто извлекает следующий элемент из одного общего итератора по списку кортежей.
Ответ №1:
super().__iter__()
возвращает, self
прежде чем for
цикл выполнит свой собственный неявный вызов iter(self)
, который запускает бесконечную рекурсию.
Из-за того, как работает for
цикл, я не видел никакого способа использовать его здесь. Вместо этого вы можете использовать явный while
цикл, чтобы избежать вызовов __iter__
.
def __iter__(self):
while True:
try:
i, j = next(self)
except StopIteration:
break
yield i
yield j
Это не обрабатывается self
как итерируемое, только как итератор.
Комментарии:
1. Я вижу причину. Но можете ли вы предоставить более подробный ответ? Есть ли способ исправить вторую переопределяющую проблему?