<p dir="ltr"><br>
On 5 Nov 2013 03:35, "Ron Adam" <<a href="mailto:ron3200@gmail.com">ron3200@gmail.com</a>> wrote:<br>
><br>
><br>
> This is one solution to what we can do to make slices both easier to understand and work in a much more consistent and flexible way.<br>
><br>
> This matches the slice semantics that Guido likes.<br>
> (possibly for python 4.)<br>
><br>
> The ability to pass callables along with the slice creates an easy and clean way to add new indexing modes. (As Nick suggested.)</p>
<p dir="ltr">Tuples can't really be used for this purpose, since that's incompatible with multi-dimensional indexing.</p>
<p dir="ltr">However, I also agree containment would be a better way to go than subclassing.</p>
<p dir="ltr">I'm currently thinking that a fourth "adjust" argument to the slice constructor may work, and call that from the indices method as:</p>
<p dir="ltr"> def adjust_indices(start, stop, step, length):<br>
...</p>
<p dir="ltr">The values passed in would be those from the slice constructor plus the length passed to the indices method. The only preconditioning would be the check for a non-zero step. </p>
<p dir="ltr">The result would be used as the result of the indices method.</p>
<p dir="ltr">Cheers,<br>
Nick.</p>
<p dir="ltr">><br>
> Overall, this makes everything simpler and easier to do. :-)<br>
><br>
><br>
> Cheers,<br>
> Ron<br>
><br>
><br>
> """<br>
><br>
> An improved slice implementation.<br>
><br>
> Even the C source says:<br>
><br>
> "It's harder to get right than you might think."<br>
><br>
> both in code and in understanding<br>
> This requires changing slice indexing so that<br>
> the following relationships are true.<br>
><br>
> s[i:j:k] == s[i:j][k] both in code and in understanding<br>
><br>
> s[i:j:-1] == s[i:j:1][::-1]<br>
><br>
><br>
> And it also adds the ability to apply callables to<br>
> slices and index's using the existing slice syntax.<br>
><br>
> These alterations would need to be made to the __getitem__<br>
> and __setitem__, methods of built-in types. Possibly in<br>
> Python 4.0.<br>
><br>
> *(I was not able to get a clean version of this behaviour<br>
> with the existing slice semantics. But the slice and index<br>
> behaviour of this implementation is much simpler and makes<br>
> using callables to adjust index's very easy. That seems<br>
> like a good indication that changing slices to match the<br>
> above relationships is worth doing.<br>
><br>
> It may be possible to get the current behaviour by applying<br>
> a callable to the slice like the open, closed, and ones index<br>
> examples below.<br>
> )<br>
><br>
> """<br>
><br>
> # A string sub-class for testing.<br>
><br>
> class Str(str):<br>
><br>
> def _fix_slice_indexes(self, slc):<br>
> # Replace Nones and check step value.<br>
> if isinstance(slc, int):<br>
> return slc<br>
> i, j, k = slc.start, slc.stop, slc.step<br>
> if k == 0:<br>
> raise ValueError("slice step cannot be zero")<br>
> if i == None: i = 0<br>
> if j == None: j = len(self)<br>
> if k == None: k = 1<br>
> return slice(i, j, k)<br>
><br>
> def __getitem__(self, args):<br>
> """<br>
> Gets a item from a string with either an<br>
> index, or slice. Apply any callables to the<br>
> slice if they are pressent.<br>
><br>
> Valid inputes...<br>
> i<br>
> (i, callables ...)<br>
> slice()<br>
> (slice(), callables ...)<br>
><br>
> """<br>
> # Apply callables if any.<br>
> if isinstance(args, tuple):<br>
> slc, *callables = args<br>
> slc = self._fix_slice_indexes(slc)<br>
> for fn in callables:<br>
> slc = fn(self, slc)<br>
> else:<br>
> slc = self._fix_slice_indexes(args)<br>
><br>
> # Just an index<br>
> if isinstance(slc, int):<br>
> return str.__getitem__(self, slc)<br>
><br>
> # Handle slice.<br>
> rval = []<br>
> i, j, k = slc.start, slc.stop, slc.step<br>
> ix = i if k > 0 else j-1<br>
> while i <= ix < j:<br>
> rval.append(str.__getitem__(self, ix))<br>
> ix += k<br>
> return type(self)('').join(rval)<br>
><br>
><br>
> """<br>
> These end with 'i' to indicate they make index adjustments,<br>
> and also to make them less likely to clash with other<br>
> functions.<br>
><br>
> Some of these are so simple, you'd probably just<br>
> adjust the index directly, ie.. reversei. But<br>
> they make good examples of what is possible. And possible<br>
> There are other uses as well.<br>
><br>
> Because they are just objects passed in, the names aren't<br>
> important. They can be called anything and still work, and<br>
> the programmer is free to create new alternatives.<br>
> """<br>
><br>
> def reversei(obj, slc):<br>
> """Return a new slice with reversed step."""<br>
> if isinstance(slc, slice):<br>
> i, j, k = slc.start, slc.stop, slc.step<br>
> return slice(i, j, -k)<br>
> return slc<br>
><br>
> def trimi(obj, slc):<br>
> """Trim left and right so an IndexError is not produced."""<br>
> if isinstance(slc, slice):<br>
> ln = len(obj)<br>
> i, j, k = slc.start, slc.stop, slc.step<br>
> if i<0: i = 0<br>
> if j>ln: j = ln<br>
> return slice(i, j, k)<br>
> return slc<br>
><br>
> def openi(obj, slc):<br>
> """Open interval - Does not include end points."""<br>
> if isinstance(slc, slice):<br>
> i, j, k = slc.start, slc.stop, slc.step<br>
> return slice(i+1, j, k)<br>
> return slc<br>
><br>
> def closedi(obj, slc):<br>
> """Closed interval - Includes end points."""<br>
> if isinstance(slc, slice):<br>
> i, j, k = slc.start, slc.stop, slc.step<br>
> return slice(i, j+1, k)<br>
> return slc<br>
><br>
> def onei(obj, slc):<br>
> """First element is 1 instead of zero."""<br>
> if isinstance(slc, slice):<br>
> i, j, k = slc.start, slc.stop, slc.step<br>
> return slice(i-1, j-1, k)<br>
> return slc - 1<br>
><br>
><br>
><br>
> def _test_cases1():<br>
> """<br>
><br>
> # test string<br>
> >>> s = Str('0123456789')<br>
><br>
> # |0|1|2|3|4|5|6|7|8|9|<br>
> # 0 1 2 3 4 5 6 7 8 9 10<br>
> # 10 9 8 7 6 5 4 3 2 1 0<br>
><br>
><br>
> >>> s[:]<br>
> '0123456789'<br>
><br>
> >>> s[:, trimi]<br>
> '0123456789'<br>
><br>
> >>> s[:, reversei]<br>
> '9876543210'<br>
><br>
> >>> s[:, reversei, trimi]<br>
> '9876543210'<br>
><br>
> >>> s[::, trimi, reversei]<br>
> '9876543210'<br>
><br>
><br>
> # Right side bigger than len(s)<br>
><br>
> >>> s[:100]<br>
> Traceback (most recent call last):<br>
> IndexError: string index out of range<br>
><br>
> >>> s[:100, trimi]<br>
> '0123456789'<br>
><br>
> >>> s[:100, trimi, reversei]<br>
> '9876543210'<br>
><br>
> >>> s[:100, reversei]<br>
> Traceback (most recent call last):<br>
> IndexError: string index out of range<br>
><br>
> >>> s[:100, reversei, trimi]<br>
> '9876543210'<br>
><br>
><br>
> # Left side smaller than 0.<br>
><br>
> >>> s[-100:]<br>
> Traceback (most recent call last):<br>
> IndexError: string index out of range<br>
><br>
> >>> s[-100:, trimi]<br>
> '0123456789'<br>
><br>
> >>> s[-100:, trimi, reversei]<br>
> '9876543210'<br>
><br>
><br>
> # Slice bigger than s.<br>
><br>
> >>> s[-100:100]<br>
> Traceback (most recent call last):<br>
> IndexError: string index out of range<br>
><br>
> >>> s[-100:100, trimi]<br>
> '0123456789'<br>
><br>
><br>
> # Slice smaller than s.<br>
><br>
> >>> s[3:7]<br>
> '3456'<br>
><br>
> >>> s[3:7, reversei]<br>
> '6543'<br>
><br>
><br>
><br>
> # From left With negative step.<br>
><br>
> >>> s[::-1]<br>
> '9876543210'<br>
><br>
> >>> s[::-1, reversei]<br>
> '0123456789'<br>
><br>
> >>> s[:100:-1, trimi] # j past right side<br>
> '9876543210'<br>
><br>
> >>> s[-100::-1, trimi] # i before left side<br>
> '9876543210'<br>
><br>
> >>> s[-100:100:-1, trimi, reversei] # slice is bigger<br>
> '0123456789'<br>
><br>
><br>
><br>
> # Null results<br>
><br>
> >>> s[7:3:1, trimi]<br>
> ''<br>
><br>
> >>> s[7:3:-1, trimi]<br>
> ''<br>
><br>
><br>
> # Check None values.<br>
><br>
> >>> s[:]<br>
> '0123456789'<br>
><br>
> >>> s[None:None]<br>
> '0123456789'<br>
><br>
> >>> s[None:None:None]<br>
> '0123456789'<br>
><br>
> >>> s[:: 1]<br>
> '0123456789'<br>
><br>
> >>> s[::-1]<br>
> '9876543210'<br>
><br>
> >>> s[None:None:1]<br>
> '0123456789'<br>
><br>
> >>> s[None:None:-1]<br>
> '9876543210'<br>
><br>
><br>
> # Check error messages.<br>
><br>
> >>> s[0:0:0:0]<br>
> Traceback (most recent call last):<br>
> SyntaxError: invalid syntax<br>
><br>
> >>> s[5:5:0]<br>
> Traceback (most recent call last):<br>
> ValueError: slice step cannot be zero<br>
><br>
><br>
><br>
> # And various other combinations.<br>
><br>
> >>> s = Str('123456789')<br>
><br>
> >>> s[3, onei]<br>
> '3'<br>
><br>
> >>> s[4:8, onei]<br>
> '4567'<br>
><br>
> >>> s[4:8, onei, openi]<br>
> '567'<br>
><br>
> >>> s[4:8, onei, closedi]<br>
> '45678'<br>
><br>
><br>
> """<br>
><br>
><br>
> def _test():<br>
> import doctest<br>
> print(doctest.testmod(verbose=False))<br>
><br>
><br>
> if __name__=="__main__":<br>
> _test()<br>
><br>
><br>
> _______________________________________________<br>
> Python-ideas mailing list<br>
> <a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/python-ideas">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
</p>