tags:

views:

96

answers:

5

If I have a list in python, how can I create a reference to part of the list? For example:

myList = ["*", "*", "*",  "*", "*", "*", "*", "*", "*"]

listPart = myList[0:7:3] #This makes a new list, which is not what I want

myList[0] = "1"

listPart[0]

"1"

Is this possible and if so how would I code it?

Cheers, Joe

+2  A: 

Use a slice object or an islice iterator?

http://docs.python.org/library/functions.html#slice

Bastien Léonard
+1  A: 

I think that it is impossible. It would lead to many possible errors, for example: what when you append the list which is reference to part of a bigger list? Shall next element in big list be replaced, or inserted?

As far as I know, silce is internal mechanism for getting elements of the list. They do not create new list object, referencing to parts of older list object. Islice just iterates over the elements given by slice, it is also not the reference, but the actual object - changing it doesn't affect original list. Or am I mistaken?

As in comment, and that solution contributes really to Mr. Bastien, you can do:

sliceobject = slice(0,7,3)
for i in xrange(sliceobject.start, sliceobject.stop, sliceobject.step)
    myList[i] = whatever

That way you can access each specified element of your list by reference.

raceCh-
I think you're right. But to me it seems that something like a tuple (list, slice) could fit the OP needs.
Bastien Léonard
Hopefully. Other option might be using slice by hand (for i in xrange(sliceobject.start, sliceobject.stop, sliceobject.step) mylist[i] = whatever)
raceCh-
+2  A: 

There's nothing in python that really does what you want. Basically you want to write some sort of proxy object.

Alex Gaynor
+1  A: 

You can write a list view type. Here is something I have written as experiment, it is by no means guaranteed to be complete or bug-free

class listview (object):
    def __init__(self, data, start, end):
        self.data = data
        self.start, self.end = start, end
    def __repr__(self):
        return "<%s %s>" % (type(self).__name__, list(self))
    def __len__(self):
        return self.end - self.start
    def __getitem__(self, idx):
        if isinstance(idx, slice):
            return [self[i] for i in xrange(*idx.indices(len(self)))]
        if idx >= len(self):
            raise IndexError
        idx %= len(self)
        return self.data[self.start+idx]
    def __setitem__(self, idx, val):
        if isinstance(idx, slice):
            start, stop, stride = idx.indices(len(self))
            for i, v in zip(xrange(start, stop, stride), val):
                self[i] = v
            return
        if idx >= len(self):
            raise IndexError(idx)
        idx %= len(self)
        self.data[self.start+idx] = val


L = range(10)

s = listview(L, 2, 5)

print L
print s
print len(s)
s[:] = range(3)
print s[:]
print L

Output:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
<listview [2, 3, 4]>
3
[0, 1, 2]
[0, 1, 0, 1, 2, 5, 6, 7, 8, 9]

You may assign to indices in the listview, and it will reflect on the underlying list. However,it does not make sense to define append or similar actions on the listview. It may also break if the underlying list changes in length.

kaizer.se
A: 

I think the ListView suggestion may just be what I need.

Cheers, Joe

joe