我正在尝试为容器编写自定义包装器类。为了实现迭代器 - 协议,我提供__iter__
和__next__
并访问我提供的单个项目__getitem__
:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals, with_statement
from future_builtins import *
import numpy as np
class MyContainer(object):
def __init__(self, value):
self._position = 0
self.value = value
def __str__(self):
return str(self.value)
def __len__(self):
return len(self.value)
def __getitem__(self, key):
return self.value[key]
def __iter__(self):
return self
def next(self):
if (self._position >= len(self.value)):
raise StopIteration
else:
self._position += 1
return self.value[self._position - 1]
到目前为止,一切都按预期工作,e。 G。在尝试这样的事情时:
if __name__ == '__main__':
a = MyContainer([1,2,3,4,5])
print(a)
iter(a) is iter(a)
for i in a:
print(i)
print(a[2])
但是在尝试使用numpy.maximum
时遇到了问题:
b= MyContainer([2,3,4,5,6])
np.maximum(a,b)
提升" ValueError: cannot copy sequence with size 5 to array axis with dimension 0
"。
当注释掉__iter__
方法时,我会返回一个NumPy数组,其中包含正确的结果(不再符合迭代器协议):
print(np.maximum(a,b)) # results in [2 3 4 5 6]
在评论__getitem__
时,我会找回MyContainer
print(np.maximum(a,b)) # results in [2 3 4 5 6]
但我失去了对个别物品的访问权。
有没有办法一起实现所有三个目标(Iterator-Protocol,__getitem__
和numpy.maximum
工作?我有什么根本性的错误吗?
要注意:实际的包装器类具有更多功能,但这是我可以重现行为的最小示例。
(Python 2.7.12,NumPy 1.11.1)
答案 0 :(得分:1)
您的容器是它自己的迭代器,它极大地限制了它。你只能迭代每个容器一次,之后,它被认为是#34;空的"就迭代协议而言。
请尝试使用您的代码查看:
c = MyContainer([1,2,3])
l1 = list(c) # the list constructor will call iter on its argument, then consume the iterator
l2 = list(c) # this one will be empty, since the container has no more items to iterate on
如果您没有提供__iter__
方法,但确实实现了__len__
方法和接受小整数索引的__getitem__
方法,那么Python将使用__getitem__
迭代。这样的迭代可以多次完成,因为创建的迭代器对象都是彼此不同的。
如果您在课程中使用__iter__
方法后尝试上述代码,则两个列表都会[1, 2, 3]
,如预期的那样。您还可以修复自己的__iter__
方法,以便它返回独立的迭代器。例如,您可以从内部序列返回一个迭代器:
def __iter__(self):
return iter(self.value)
或者,正如Bakuriu的评论所示:
def __iter__(self):
return (self[i] for i in range(len(self))
如果您使用__getitem__
方法但没有__iter__
方法,则后一版本基本上是Python将为您提供的。