funkyHat / listish

A collection of lazy, repeatably consumable list- & tuple-like objects which wrap any iterator or iterable.
Apache License 2.0
1 stars 3 forks source link

do 'the right thing' if a list, tuple, listish, range/xrange is passed in. #3

Open graingert opened 8 years ago

graingert commented 8 years ago

lists, tuples and listish already support indexing

range/xrange have varying magic behaviour depending on CPython 2, CPython 3 or PyPy

graingert commented 8 years ago

PyPy range objects internally behave like list-ishes

graingert commented 8 years ago

I suspect the trick is to try and pass-through index lookups when not passed a generator?

funkyHat commented 8 years ago

Yep python3 ranges are list-ish too. Lookups should be done that way you're right. We are also working on sensible (i.e. space-efficient :) support for modifications to the listish even if the underlying iterable is immutable

Additionally I think there's an open question on whether modifying listishes if the underlying iterable is mutable. Maybe modifying the original iterable is less surprising, and if users don't want that they can always pass in a copy (difficult to go the other way around)

graingert commented 8 years ago

mutability wrapping could easily a whole new library, eg what if the items in the list are mutated?

graingert commented 8 years ago

interesting stuff in https://docs.python.org/2/library/itertools.html#itertools.tee

funkyHat commented 8 years ago

mutability wrapping is kind of half the point of listish (otherwise we'd just have made Tupleish), but good point re. mutations in the input object. As the tee docs mention it's not safe to modify the source iterable after using tee on it. We have the same problem already with mutable inputs just when reading, as if the source is modified after we read past the index where the modification occurs we will be out of step. i.e.

>>> l = [0, 1, 2, 3, 4, 5]
>>> listish = Listish(l)
>>> listish[3]
3
>>> l[1] = 'b'
>>> listish[1] != l[1]
True
>>> # and worse
>>> l.insert(3, 'd')
>>> list(iter(listish))
[0, 1, 2, 3, 3, 4, 5]
>>> l
[0, 'b', 2, 'd', 3, 4, 5]

We can't control what people might do to the list after passing it to Listish, so I suppose it should just come with a warning like itertools.tee does.

I think based on that it makes sense to ignore whether the input is mutable or not and treat it as if it isn't. (perhaps we could add a flag to __new__ in case people want to be able to ignore whether the input is immutable? e.g.

>>> repr(Listish((,), passthrough_mutables=True))
Listish
>>> repr(Listish(someiter, passthrough_mutables=True))
Listish
>>> repr(Listish([1, 2, 3, 4], passthrough_mutables=True))
[1, 2, 3, 4]
>>> repr(Listish([1, 2, 3, 4]))
Listish

(obviously we could improve our reprs but that's a separate issue :) I don't know if there's any need for this though, thoughts?)