实现__iter__和__getitem__的容器的自定义包装器

时间:2016-07-26 21:08:20

标签: python numpy

我正在尝试为容器编写自定义包装器类。为了实现迭代器 - 协议,我提供__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)

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将为您提供的。