如何在Python中实现一个行为类似于序列的最小类?

9
我正在寻找一个Python中模仿不可变序列的类的简单示例。
class MySequence()
    ...

a = MySequence()

len(a)

for i in a:
    pass

a[0]

必须实现哪些方法?

可能是构建基本的Python迭代器的重复问题。 - Andrew Hare
请查看Python文档,网址为http://docs.python.org/reference/datamodel.html#emulating-container-types。 - hochl
3
这并不是与链接问题相同的副本。在Python中,“序列”、“可迭代对象”和“迭代器”是三个不同的概念。 - Sven Marnach
2个回答

14

如果您只想能够迭代您的序列,您只需要实现返回可迭代对象的__iter__方法。最简单的方法是使用yield语句创建生成器。

class MySequence(object):
    def __iter__(self):
        yield 1
        yield 2
        yield 3

for x in MySequence():
    print x # prints 1, then 2, then 3

然而,这并不能启用像 MySequence()[1] 这样的操作。为了实现这一点,你需要实现 __getitem__ 方法,并且最好也实现 __len__ 方法。

class MySequence(object):
    def __len__(self):
        return 3

    def __getitem__(self, key):
        if key == 0:
            return 1
        elif key == 1:
            return 2
        elif key == 2:
            return 3
        else:
            raise IndexError()

s = new MySequence()

for i in range(len(s)):
    print s[i] # prints 1, then 2, then 3

for x in s:
    print x # prints 1, then 2, then 3

注意,我省略了__iter__。只要在尝试获取超出边界的值时__getitem__引发IndexError,Python就可以将其用于迭代。(如果我想更清晰地表达意思或者想要非标准的迭代行为,我仍然可以包括__iter__。)


1
你确定最后两行是正确的吗?它们对我来说看起来非常奇怪。我想你想在最后一行写 print x - sorin

5

补充@Jeremy的回答:检查值是否为通用序列的一种流行方法是使用isinstance(value, collections.Sequence)

为了使您的类型成为通用序列,它需要继承自collections.Sequence,并且这实际上提供了迭代器(和其他一些有用的函数)作为mixin,只要您提供了__len____getitem__函数。

借鉴@Jeremy的答案,一个示例类看起来像:

import collections
class MySequence(collections.Sequence):
    def __len__(self):
        return 3

    def __getitem__(self, key):
        if key == 0:
            return 1
        elif key == 1:
            return 2
        elif key == 2:
            return 3
        else:
            raise IndexError()

使用示例:

s = MySequence()

for i in range(len(s)):
    print s[i] # prints 1, then 2, then 3

for x in s:
    print x # prints 1, then 2, then 3

print isinstance(s, collections.Sequence) # prints True

print 1 in s # prints True

print list(reversed(s)) # prints [3, 2, 1]

1
collections.Sequence已经在Python的更新版本中被移动到了collections.abc.Sequence。 - Matthew Scouten

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接