如何实现一个最小的类,使其在Python中像序列一样工作?

9 投票
2 回答
7661 浏览
提问于 2025-04-17 04:53

我在寻找一个简单的示例,展示一个在Python中模拟不可变序列的类。

class MySequence()
    ...

a = MySequence()

len(a)

for i in a:
    pass

a[0]

需要实现哪些方法呢?

2 个回答

6

补充一下@Jeremy的回答:一个常用的方法来检查一个值是否是一个通用序列,就是用 isinstance(value, collections.Sequence)

为了让你的类型也能通过这个检查,它需要继承自 collections.Sequence。这样做的好处是,它会提供迭代器(还有一些其他有用的功能),只要你实现了 __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]
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__ 方法。)

撰写回答