slice notation as values?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Steven Bethard

    #16
    Re: slice notation as values?

    Antoon Pardon wrote:[color=blue]
    > On 2005-12-10, Steven Bethard <steven.bethard @gmail.com> wrote:
    >[color=green]
    >>Antoon Pardon wrote:
    >>[color=darkred]
    >>>So lets agree that tree['a':'b'] would produce a subtree. Then
    >>>I still would prefer the possibility to do something like:
    >>>
    >>> for key in tree.iterkeys(' a':'b')
    >>>
    >>>Instead of having to write
    >>>
    >>> for key in tree['a':'b'].iterkeys()
    >>>
    >>>Sure I can now do it like this:
    >>>
    >>> for key in tree.iterkeys(' a','b')
    >>>
    >>>But the way default arguments work, prevents you from having
    >>>this work in an analague way as a slice.[/color]
    >>
    >>How so? Can't you just pass the *args to the slice contstructor? E.g.::
    >>
    >> def iterkeys(self, *args):
    >> keyslice = slice(*args)
    >> ...
    >>
    >>Then you can use the slice object just as you would have otherwise.[/color]
    >
    > This doesn't work for a number of reasons,
    >
    > 1)[color=green][color=darkred]
    >>>>slice()[/color][/color]
    >
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in ?
    > TypeError: slice expected at least 1 arguments, got 0[/color]

    I wasn't sure whether or not the slice argument was optional.
    Apparently it's intended to be, so you have to make one special case:

    def iterkeys(self, *args):
    keyslice = args and slice(*args) or slice(None, None, None)
    [color=blue]
    > 2) It doens't give a clear way to indicate the following
    > kind of slice: tree.iterkeys(' a':). Because of the
    > follwing:
    >[color=green][color=darkred]
    >>>>slice('a' )[/color][/color]
    > slice(None, 'a', None)
    >
    > which would be equivallent to tree.iterkeys(: 'a')[/color]

    Well, it certainly gives a way to indicate it:

    tree.iterkeys(N one, 'a')

    Whether or not it's a "clear" way is too subjective of a topic for me to
    get into. That's best left to Guido[1]. My point is that it *does*
    work, and covers (or can be slightly altered to cover) all the
    functionality you want. That doesn't mean you have to like the API for
    it, of course.

    STeVe

    [1] By which I mean that you should submit a PEP on the idea, and let
    Guido decide which way is prettier. Just be sure to give all the
    equivalent examples - i.e. calling the slice constructor with the
    appropriate arguments.

    Comment

    • Bengt Richter

      #17
      Re: slice notation as values?

      On 10 Dec 2005 12:07:12 -0800, "Devan L" <devlai@gmail.c om> wrote:
      [color=blue]
      >
      >Antoon Pardon wrote:[color=green]
      >> On 2005-12-10, Duncan Booth <duncan.booth@i nvalid.invalid> wrote:[/color]
      >[snip][color=green][color=darkred]
      >> >> I also think that other functions could benefit. For instance suppose
      >> >> you want to iterate over every second element in a list. Sure you
      >> >> can use an extended slice or use some kind of while. But why not
      >> >> extend enumerate to include an optional slice parameter, so you could
      >> >> do it as follows:
      >> >>
      >> >> for el in enumerate(lst,: :2)
      >> >
      >> > 'Why not'? Because it makes for a more complicated interface for something
      >> > you can already do quite easily.[/color]
      >>
      >> Do you think so? This IMO should provide (0,lst[0]), (2,lst[2]),
      >> (4,lst[4]) ...
      >>
      >> I haven't found a way to do this easily. Except for something like:
      >>
      >> start = 0:
      >> while start < len(lst):
      >> yield start, lst[start]
      >> start += 2
      >>
      >> But if you accept this, then there was no need for enumerate in the
      >> first place. So eager to learn something new, how do you do this
      >> quite easily?[/color]
      >[color=green][color=darkred]
      >>>> lst = ['ham','eggs','b acon','spam','f oo','bar','baz']
      >>>> list(enumerate( lst))[::2][/color][/color]
      >[(0, 'ham'), (2, 'bacon'), (4, 'foo'), (6, 'baz')]
      >
      >No changes to the language necessary.
      >[/color]
      Or, without creating the full list intermediately,
      [color=blue][color=green][color=darkred]
      >>> lst = ['ham','eggs','b acon','spam','f oo','bar','baz']
      >>> import itertools
      >>> list(itertools. islice(enumerat e(lst), 0, None, 2))[/color][/color][/color]
      [(0, 'ham'), (2, 'bacon'), (4, 'foo'), (6, 'baz')]

      Regards,
      Bengt Richter

      Comment

      • Duncan Booth

        #18
        Re: slice notation as values?

        Brian Beck wrote:
        [color=blue]
        > Antoon Pardon wrote:[color=green]
        >> Will it ever be possible to write things like:
        >>
        >> a = 4:9[/color]
        >
        > I made a silly recipe to do something like this a while ago, not that
        > I'd recommend using it. But I also think it wouldn't be too far-fetched
        > to allow slice creation using a syntax like the above...
        >
        > http://aspn.activestate.com/ASPN/Coo.../Recipe/415500
        >[/color]

        Another possibility would be to make the slice type itself sliceable, then
        you could write things like:[color=blue][color=green][color=darkred]
        >>> a = slice[4:9]
        >>> a[/color][/color][/color]
        slice(4, 9, None)

        Sample implementation:
        [color=blue][color=green][color=darkred]
        >>> class MetaSlice(objec t):[/color][/color][/color]
        def __getitem__(cls , item):
        return item
        def __init__(self, *args, **kw):
        return super(MetaSlice ,self).__init__ (self, *args, **kw)

        [color=blue][color=green][color=darkred]
        >>> class Slice(slice):[/color][/color][/color]
        __metaclass__=M etaSlice

        [color=blue][color=green][color=darkred]
        >>> Slice[2:3][/color][/color][/color]
        slice(2, 3, None)[color=blue][color=green][color=darkred]
        >>> Slice[:3][/color][/color][/color]
        slice(None, 3, None)[color=blue][color=green][color=darkred]
        >>> Slice[:3:-1][/color][/color][/color]
        slice(None, 3, -1)

        Comment

        • Antoon Pardon

          #19
          Re: slice notation as values?

          Op 2005-12-10, Devan L schreef <devlai@gmail.c om>:[color=blue]
          >
          > Antoon Pardon wrote:[color=green]
          >> On 2005-12-10, Duncan Booth <duncan.booth@i nvalid.invalid> wrote:[/color]
          > [snip][color=green][color=darkred]
          >> >> I also think that other functions could benefit. For instance suppose
          >> >> you want to iterate over every second element in a list. Sure you
          >> >> can use an extended slice or use some kind of while. But why not
          >> >> extend enumerate to include an optional slice parameter, so you could
          >> >> do it as follows:
          >> >>
          >> >> for el in enumerate(lst,: :2)
          >> >
          >> > 'Why not'? Because it makes for a more complicated interface for something
          >> > you can already do quite easily.[/color]
          >>
          >> Do you think so? This IMO should provide (0,lst[0]), (2,lst[2]),
          >> (4,lst[4]) ...
          >>
          >> I haven't found a way to do this easily. Except for something like:
          >>
          >> start = 0:
          >> while start < len(lst):
          >> yield start, lst[start]
          >> start += 2
          >>
          >> But if you accept this, then there was no need for enumerate in the
          >> first place. So eager to learn something new, how do you do this
          >> quite easily?[/color]
          >[color=green][color=darkred]
          >>>> lst = ['ham','eggs','b acon','spam','f oo','bar','baz']
          >>>> list(enumerate( lst))[::2][/color][/color]
          > [(0, 'ham'), (2, 'bacon'), (4, 'foo'), (6, 'baz')][/color]

          It is not about what is needed, but about convenience.

          Now let me see, in order to just iterate over the even elements
          of a list with the index of the element, you turned an iterator
          into a list, which you use to create an other list which you
          will finaly iterate over.

          If this is the proposed answer, I wonder why iterators were introduced
          in the first place. I thought iterator were went to avoid the need
          to construct and copy list when all you want is iterate and when
          I ask how to get a specific iterator you come with a construct that
          makes rather heavily use of list constructions.

          --
          Antoon Pardon

          Comment

          • Antoon Pardon

            #20
            Re: slice notation as values?

            Op 2005-12-10, Brian Beck schreef <exogen@gmail.c om>:[color=blue]
            > Antoon Pardon wrote:[color=green]
            >> Will it ever be possible to write things like:
            >>
            >> a = 4:9[/color]
            >
            > I made a silly recipe to do something like this a while ago, not that
            > I'd recommend using it. But I also think it wouldn't be too far-fetched
            > to allow slice creation using a syntax like the above...[/color]

            The point is that the syntax "4:9" is already used for slice creation.

            The python grammer is essentally saying that something like 4:9 is a
            literal, just like strings and numbers, but that this specific literal
            can only be used in a subscription.

            Look at the following:
            [color=blue][color=green][color=darkred]
            >>> import dis
            >>> def foo():[/color][/color][/color]
            .... lst[[2,3,5]]
            .... lst[8:13:21]
            ....[color=blue][color=green][color=darkred]
            >>> dis.dis(foo)[/color][/color][/color]
            2 0 LOAD_GLOBAL 0 (lst)
            3 LOAD_CONST 1 (2)
            6 LOAD_CONST 2 (3)
            9 LOAD_CONST 3 (5)
            12 BUILD_LIST 3
            15 BINARY_SUBSCR
            16 POP_TOP

            3 17 LOAD_GLOBAL 0 (lst)
            20 LOAD_CONST 4 (8)
            23 LOAD_CONST 5 (13)
            26 LOAD_CONST 6 (21)
            29 BUILD_SLICE 3
            32 BINARY_SUBSCR
            33 POP_TOP
            34 LOAD_CONST 0 (None)
            37 RETURN_VALUE

            So you see that the slice is treated in an similar way
            as the list. There is no reason why this shouldn't work
            in case we want a slice in an assignment or a function
            call.

            --
            Antoon Pardon

            Comment

            • Antoon Pardon

              #21
              Re: slice notation as values?

              Op 2005-12-11, Bengt Richter schreef <bokr@oz.net> :[color=blue]
              > On 10 Dec 2005 12:07:12 -0800, "Devan L" <devlai@gmail.c om> wrote:
              >[color=green]
              >>
              >>Antoon Pardon wrote:[color=darkred]
              >>> On 2005-12-10, Duncan Booth <duncan.booth@i nvalid.invalid> wrote:[/color]
              >>[snip][color=darkred]
              >>> >> I also think that other functions could benefit. For instance suppose
              >>> >> you want to iterate over every second element in a list. Sure you
              >>> >> can use an extended slice or use some kind of while. But why not
              >>> >> extend enumerate to include an optional slice parameter, so you could
              >>> >> do it as follows:
              >>> >>
              >>> >> for el in enumerate(lst,: :2)
              >>> >
              >>> > 'Why not'? Because it makes for a more complicated interface for something
              >>> > you can already do quite easily.
              >>>
              >>> Do you think so? This IMO should provide (0,lst[0]), (2,lst[2]),
              >>> (4,lst[4]) ...
              >>>
              >>> I haven't found a way to do this easily. Except for something like:
              >>>
              >>> start = 0:
              >>> while start < len(lst):
              >>> yield start, lst[start]
              >>> start += 2
              >>>
              >>> But if you accept this, then there was no need for enumerate in the
              >>> first place. So eager to learn something new, how do you do this
              >>> quite easily?[/color]
              >>[color=darkred]
              >>>>> lst = ['ham','eggs','b acon','spam','f oo','bar','baz']
              >>>>> list(enumerate( lst))[::2][/color]
              >>[(0, 'ham'), (2, 'bacon'), (4, 'foo'), (6, 'baz')]
              >>
              >>No changes to the language necessary.
              >>[/color]
              > Or, without creating the full list intermediately,
              >[color=green][color=darkred]
              > >>> lst = ['ham','eggs','b acon','spam','f oo','bar','baz']
              > >>> import itertools
              > >>> list(itertools. islice(enumerat e(lst), 0, None, 2))[/color][/color]
              > [(0, 'ham'), (2, 'bacon'), (4, 'foo'), (6, 'baz')][/color]

              As far as I understand use of this idiom can turn an O(n)
              algorithm into an O(n^2) algorithm.

              Suppose I have a list with 10 000 elements and I want
              the sum of the first 100, the sum of the second 100 ...

              One way to do that would be:

              for i in xrange(0,10000, 100):
              sum(itertools.i slice(lst, i, i+100))

              But itertools.islic e would each time start from the begining
              of the list and iterate over i elements before giving 100
              elements to sum. Which would make this implementation O(n^2)
              instead of O(n).

              --
              Antoon Pardon

              Comment

              • bonono@gmail.com

                #22
                Re: slice notation as values?


                Antoon Pardon wrote:[color=blue]
                > Suppose I have a list with 10 000 elements and I want
                > the sum of the first 100, the sum of the second 100 ...
                >
                > One way to do that would be:
                >
                > for i in xrange(0,10000, 100):
                > sum(itertools.i slice(lst, i, i+100))
                >
                > But itertools.islic e would each time start from the begining
                > of the list and iterate over i elements before giving 100
                > elements to sum. Which would make this implementation O(n^2)
                > instead of O(n).[/color]
                Can you use iter for this situation ?

                a=iter(lst)
                for i in xrange(0,10000, 100):
                sum(itertools.i slice(a,100))

                Comment

                • Bengt Richter

                  #23
                  Re: slice notation as values?

                  On 12 Dec 2005 08:34:37 GMT, Antoon Pardon <apardon@forel. vub.ac.be> wrote:
                  [color=blue]
                  >Op 2005-12-10, Devan L schreef <devlai@gmail.c om>:[color=green]
                  >>
                  >> Antoon Pardon wrote:[color=darkred]
                  >>> On 2005-12-10, Duncan Booth <duncan.booth@i nvalid.invalid> wrote:[/color]
                  >> [snip][color=darkred]
                  >>> >> I also think that other functions could benefit. For instance suppose
                  >>> >> you want to iterate over every second element in a list. Sure you
                  >>> >> can use an extended slice or use some kind of while. But why not
                  >>> >> extend enumerate to include an optional slice parameter, so you could
                  >>> >> do it as follows:
                  >>> >>
                  >>> >> for el in enumerate(lst,: :2)[/color][/color][/color]

                  If you are willing to use square brackets, you can spell it
                  [color=blue][color=green][color=darkred]
                  >>> for el in enoomerate[lst, ::2]: print el,[/color][/color][/color]

                  (see below ;-)
                  [color=blue][color=green][color=darkred]
                  >>> >
                  >>> > 'Why not'? Because it makes for a more complicated interface for something
                  >>> > you can already do quite easily.
                  >>>
                  >>> Do you think so? This IMO should provide (0,lst[0]), (2,lst[2]),
                  >>> (4,lst[4]) ...
                  >>>
                  >>> I haven't found a way to do this easily. Except for something like:
                  >>>
                  >>> start = 0:
                  >>> while start < len(lst):
                  >>> yield start, lst[start]
                  >>> start += 2
                  >>>
                  >>> But if you accept this, then there was no need for enumerate in the
                  >>> first place. So eager to learn something new, how do you do this
                  >>> quite easily?[/color]
                  >>[color=darkred]
                  >>>>> lst = ['ham','eggs','b acon','spam','f oo','bar','baz']
                  >>>>> list(enumerate( lst))[::2][/color]
                  >> [(0, 'ham'), (2, 'bacon'), (4, 'foo'), (6, 'baz')][/color]
                  >
                  >It is not about what is needed, but about convenience.
                  >
                  >Now let me see, in order to just iterate over the even elements
                  >of a list with the index of the element, you turned an iterator
                  >into a list, which you use to create an other list which you
                  >will finaly iterate over.
                  >
                  >If this is the proposed answer, I wonder why iterators were introduced
                  >in the first place. I thought iterator were went to avoid the need
                  >to construct and copy list when all you want is iterate and when
                  >I ask how to get a specific iterator you come with a construct that
                  >makes rather heavily use of list constructions.
                  >[/color]
                  Just for you ;-)
                  [color=blue][color=green][color=darkred]
                  >>> import itertools
                  >>> class enoomerate(obje ct):[/color][/color][/color]
                  ... def __getitem__(sel f, seq):
                  ... if isinstance(seq, tuple):
                  ... seq, slc = seq
                  ... else:
                  ... slc = slice(None)
                  ... if not isinstance(slc, slice): slc = slice(None, slc)
                  ... return itertools.islic e(enumerate(seq ), slc.start or 0, slc.stop, slc.step or 1)
                  ...[color=blue][color=green][color=darkred]
                  >>> enoomerate = enoomerate()
                  >>>
                  >>> import string
                  >>> lst = list(string.asc ii_lowercase) # legit list, though could use the string
                  >>> for el in enoomerate[lst, ::2]: print el,[/color][/color][/color]
                  ...
                  (0, 'a') (2, 'c') (4, 'e') (6, 'g') (8, 'i') (10, 'k') (12, 'm') (14, 'o') (16, 'q') (18, 's') (
                  20, 'u') (22, 'w') (24, 'y')[color=blue][color=green][color=darkred]
                  >>> for el in enoomerate[lst, 3::3]: print el,[/color][/color][/color]
                  ...
                  (3, 'd') (6, 'g') (9, 'j') (12, 'm') (15, 'p') (18, 's') (21, 'v') (24, 'y')[color=blue][color=green][color=darkred]
                  >>> for el in enoomerate[lst, 3]: print el,[/color][/color][/color]
                  ...
                  (0, 'a') (1, 'b') (2, 'c')[color=blue][color=green][color=darkred]
                  >>> for el in enoomerate[lst, 3:6]: print el,[/color][/color][/color]
                  ...
                  (3, 'd') (4, 'e') (5, 'f')[color=blue][color=green][color=darkred]
                  >>> for el in enoomerate[lst, 3:6:2]: print el,[/color][/color][/color]
                  ...
                  (3, 'd') (5, 'f')

                  Regards,
                  Bengt Richter

                  Comment

                  • Antoon Pardon

                    #24
                    Re: slice notation as values?

                    Op 2005-12-12, Bengt Richter schreef <bokr@oz.net> :[color=blue]
                    > On 12 Dec 2005 08:34:37 GMT, Antoon Pardon <apardon@forel. vub.ac.be> wrote:
                    >[color=green]
                    >>Op 2005-12-10, Devan L schreef <devlai@gmail.c om>:[color=darkred]
                    >>>
                    >>> Antoon Pardon wrote:
                    >>>> On 2005-12-10, Duncan Booth <duncan.booth@i nvalid.invalid> wrote:
                    >>> [snip]
                    >>>> >> I also think that other functions could benefit. For instance suppose
                    >>>> >> you want to iterate over every second element in a list. Sure you
                    >>>> >> can use an extended slice or use some kind of while. But why not
                    >>>> >> extend enumerate to include an optional slice parameter, so you could
                    >>>> >> do it as follows:
                    >>>> >>
                    >>>> >> for el in enumerate(lst,: :2)[/color][/color]
                    >
                    > If you are willing to use square brackets, you can spell it[/color]

                    Hmm, I have to think about that.
                    [color=blue][color=green][color=darkred]
                    > >>> for el in enoomerate[lst, ::2]: print el,[/color][/color]
                    >
                    > (see below ;-)
                    >[color=green]
                    >> [ ... ][/color][/color]
                    [color=blue]
                    > Just for you ;-)[/color]

                    Thank you.
                    [color=blue][color=green][color=darkred]
                    > >>> import itertools
                    > >>> class enoomerate(obje ct):[/color][/color]
                    > ... def __getitem__(sel f, seq):
                    > ... if isinstance(seq, tuple):
                    > ... seq, slc = seq
                    > ... else:
                    > ... slc = slice(None)
                    > ... if not isinstance(slc, slice): slc = slice(None, slc)
                    > ... return itertools.islic e(enumerate(seq ), slc.start or 0, slc.stop, slc.step or 1)
                    > ...[color=green][color=darkred]
                    > >>> enoomerate = enoomerate()
                    > >>>
                    > >>> import string
                    > >>> lst = list(string.asc ii_lowercase) # legit list, though could use the string
                    > >>> for el in enoomerate[lst, ::2]: print el,[/color][/color][/color]

                    I am wondering a bit. Could this be turned into a decorator?

                    I don't have much experience with decorators, so I'll have to
                    think this through for a wgile. The idea would be a class
                    to be used as decorator that would turn a function returning
                    an iterator in a slicable iterator. Something like the following
                    maybe:

                    class SliceIterator(o bject):

                    def __init__(self,f unc):
                    self.func = func

                    def __getitem__(sel f, args):
                    if isinstance(args , tuple)
                    return self.func(*args )
                    else:
                    return self.func(args)

                    def __iter__(self):
                    return self.func(slice (None, None, None))

                    I could then write something like:

                    @SliceIterator
                    def srange(sl):
                    v = sl.stop
                    while v < sl.start:
                    yield v
                    v += sl.step


                    And use it as:

                    for i in srange[23:67:3]:
                    ...

                    Hmm, I have to play with this a bit. Thanks for the idea.

                    --
                    Antoon Pardon

                    Comment

                    Working...