Python是否有简写符号表示传递部分列表而没有副本?

时间:2015-12-08 00:08:09

标签: python python-3.x

假设我将以下伪代码转换为Python。关于具体表示为1st half of A的参数,Python是否有像A[1..n/2]这样的机制(我不时看到的另一种伪代码快捷方式)不需要复制来传递部分列表作为参数?

Count(array A, length n)
    if n = 1 return 0
    else
        x = Count(1st half of A, n/2)
        y = Count(2nd half of A, n/2)
    return x + y

如果没有这样的机制,我会根据需要传递索引。

3 个答案:

答案 0 :(得分:3)

答案是否定的。您必须传递索引(或slice个对象)。

您还可以编写一个list子类,通过将“视图”返回到原始列表而不是副本来处理切片。我实际上已经解决了几次,并且发现完全正确是很棘手的,但是由于您的应用程序不需要负索引,切片分配或跳过参数,所以它变得更加容易。这是一个快速尝试:

class ListWithAView(list):

    class ListView(object):
        def __init__(self, list, start, stop, step):
            self.list  = list
            self.start = start
            self.stop  = stop
            self.step  = step

        def __iter__(self):
            for i in xrange(self.start, self.stop, self.step):
                yield self.list[i]

        def __len__(self):
            return (self.stop - self.start) / self.step

        def __getitem__(self, i):
            if isinstance(i, slice):
                return type(self)(self.list, (i.start or 0) + self.start,
                                  min(self.start + (i.stop or 0), self.stop),
                                  i.step * self.step if i.step else self.step)
            if isinstance(i, int) and i < len(self):
                return self.list[i+self.start]
            raise IndexError("invalid index: %r" % i)

        def __setitem__(self, i, v):
            if isinstance(i, int):
                self.list[i+self.start] = v
            else:
                raise IndexError("invalid index: %r" % i)

        def __repr__(self):
            return "<slice [%s:%s:%s] of list id 0x%08x>: %s" % (self.start, self.stop, self.step, id(self.list), self)

        def __str__(self):
            return str(list(self))

        __str__ = __repr__

    @property
    def view(self):
        return self.ListView(self, 0, len(self), 1)

此列表子类的view属性返回一个ListView对象,其行为与列表非常相似,但是获取并设置基础列表中的数据,而不是存储任何项本身。返回的对象最初引用整个列表,但如果需要可以进一步切片。为简单起见,不处理否定步骤,您不能进行切片分配,只需单个项目。

快速演示:

seq = ListViwthAView(range(100))
view = seq.view[10:20][5:7]
view[0] = 1337
print seq[15]    # 1337

答案 1 :(得分:2)

您可以在此处使用slice个对象,但遗憾的是,没有__len__方法,因此您必须使用(s.start + s.stop)/2来计算长度。任何时候你明智地“实现”子阵列(当然创建副本),你可以使用A[s]

def count(A, s=None):
    if s is None:
        s=slice(0, len(A))
    if s.start + 1  == s.stop:
        return 1
    else:
        x = count(A, slice(s.start, (s.start + s.stop)/2))
        y = count(A, slice((s.start + s.stop)/2, s.stop))
    return x + y

print count([1,2,3,4,5])

答案 2 :(得分:2)

在您的示例中,最佳解决方案是按照您的建议传递列表和索引。

如果您不需要索引切片(例如,如果仅在列表的前半部分和后半部分上使用迭代器就足够了),则可以使用islice函数来自{{ 1}}。 E.g。

itertools