Tuple assignment and generators?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Tim Chase

    #1

    Tuple assignment and generators?

    Just as a pedantic exercise to try and understand Python a
    bit better, I decided to try to make a generator or class
    that would allow me to unpack an arbitrary number of
    calculatible values. In this case, just zeros (though I
    just to prove whatever ends up working, having a counting
    generator would be nice). The target syntax would be
    something like
    [color=blue][color=green][color=darkred]
    >>> a,b,c = zeros()
    >>> q,r,s,t,u,v = zeros()[/color][/color][/color]

    where "zeros()" returns an appropriately sized tuple/list of
    zeros.

    I've tried a bit of googling, but all my attempts have just
    ended up pointing to pages that blithly describe tuple
    assignment, not the details of what methods are called on an
    object in the process.

    My first thought was to get it to use a generator:

    def zeros():
    while 1: yield 0

    However, I get back a "ValueError : too many values to
    unpack" result.

    As a second attempt, I tried a couple of attempts at classes
    (I started with the following example class, only derived
    from "object" rather than "list", but it didn't have any
    better luck):
    [color=blue][color=green][color=darkred]
    >>> class zeros(list):[/color][/color][/color]
    .... def __getitem__(sel f,i):
    .... return 0
    ....[color=blue][color=green][color=darkred]
    >>> z = zeros()
    >>> a,b,c = z[/color][/color][/color]
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    ValueError: need more than 0 values to unpack


    It looks like I need to have a pre-defined length, but I'm
    having trouble figuring out what sorts of things need to be
    overridden. It seems like I sorta need a

    def __len__(self):
    return INFINITY

    so it doesn't choke on it. However, how to dupe the
    interpreter into really believing that the object has the
    desired elements is escaping me. Alternatively if there was
    a "doYouHaveThisM anyElements" pseudo-function that was
    called, I could lie and always return true.

    Any hints on what I'm missing?

    Thanks,

    -tkc








  • Diez B. Roggisch

    #2
    Re: Tuple assignment and generators?

    Tim Chase wrote:
    [color=blue]
    > Just as a pedantic exercise to try and understand Python a
    > bit better, I decided to try to make a generator or class
    > that would allow me to unpack an arbitrary number of
    > calculatible values. In this case, just zeros (though I
    > just to prove whatever ends up working, having a counting
    > generator would be nice). The target syntax would be
    > something like[/color]

    <snip/>

    By using this:




    I came up with a small decorator doing that:

    import inspect, dis

    def expecting():
    """Return how many values the caller is expecting"""
    f = inspect.current frame()
    f = f.f_back.f_back
    c = f.f_code
    i = f.f_lasti
    bytecode = c.co_code
    instruction = ord(bytecode[i+3])
    if instruction == dis.opmap['UNPACK_SEQUENC E']:
    howmany = ord(bytecode[i+4])
    return howmany
    elif instruction == dis.opmap['POP_TOP']:
    return 0
    return 1

    def variably_unpack (f):
    def d(*args, **kwargs):
    r = f(*args, **kwargs)
    exp = expecting()
    if exp < 2:
    return exp
    return (r.next() for i in xrange(exp))
    return d

    @variably_unpac k
    def test():
    def gen():
    i = 0
    while True:
    yield i
    i += 1
    return gen()



    a, b, c = test()

    print a,b,c

    a, b, c, d = test()

    print a,b,c, d



    Diez


    Comment

    • Larry Bates

      #3
      Re: Tuple assignment and generators?


      Tim Chase wrote:[color=blue]
      > Just as a pedantic exercise to try and understand Python a bit better, I
      > decided to try to make a generator or class that would allow me to
      > unpack an arbitrary number of calculatible values. In this case, just
      > zeros (though I just to prove whatever ends up working, having a
      > counting generator would be nice). The target syntax would be something
      > like
      >[color=green][color=darkred]
      >>>> a,b,c = zeros()
      >>>> q,r,s,t,u,v = zeros()[/color][/color]
      >
      > where "zeros()" returns an appropriately sized tuple/list of zeros.
      >
      > I've tried a bit of googling, but all my attempts have just ended up
      > pointing to pages that blithly describe tuple assignment, not the
      > details of what methods are called on an object in the process.
      >
      > My first thought was to get it to use a generator:
      >
      > def zeros():
      > while 1: yield 0
      >
      > However, I get back a "ValueError : too many values to unpack" result.
      >
      > As a second attempt, I tried a couple of attempts at classes (I started
      > with the following example class, only derived from "object" rather than
      > "list", but it didn't have any better luck):
      >[color=green][color=darkred]
      >>>> class zeros(list):[/color][/color]
      > ... def __getitem__(sel f,i):
      > ... return 0
      > ...[color=green][color=darkred]
      >>>> z = zeros()
      >>>> a,b,c = z[/color][/color]
      > Traceback (most recent call last):
      > File "<stdin>", line 1, in ?
      > ValueError: need more than 0 values to unpack
      >
      >
      > It looks like I need to have a pre-defined length, but I'm having
      > trouble figuring out what sorts of things need to be overridden. It
      > seems like I sorta need a
      >
      > def __len__(self):
      > return INFINITY
      >
      > so it doesn't choke on it. However, how to dupe the interpreter into
      > really believing that the object has the desired elements is escaping
      > me. Alternatively if there was a "doYouHaveThisM anyElements"
      > pseudo-function that was called, I could lie and always return true.
      >
      > Any hints on what I'm missing?
      >
      > Thanks,
      >
      > -tkc
      >
      >[/color]
      While I have never needed anything like this in my 5 years of Python
      programming, here is a way:

      a,b,c = 3*[0]
      q,r,s,t,u,v = 6*[0]

      of if you like:

      def zeros(num):
      return num*[0]

      a,b,c = zeros(3)
      q,r,s,t,u,v = zeros(6)

      I think the reason I don't every use anything like this is that
      you don't need to initialize variables in Python to zero and I would
      probably use a list instead of individual variables like q,r,s,t,u,v.

      -Larry Bates

      Comment

      • Ant

        #4
        Re: Tuple assignment and generators?

        I don't think he was explicitly wanting to initialize things to zero,
        but rather unpack an arbitrary sequence into a tuple (could perhaps be
        the fibonnacci sequence for example).

        How about:
        [color=blue][color=green][color=darkred]
        >>> def zeros(count):[/color][/color][/color]
        .... for i in range(count):
        .... yield 0
        ....[color=blue][color=green][color=darkred]
        >>> a,b,c = zeros(3)
        >>> a[/color][/color][/color]
        0[color=blue][color=green][color=darkred]
        >>> b[/color][/color][/color]
        0[color=blue][color=green][color=darkred]
        >>> c[/color][/color][/color]
        0

        Comment

        • Just

          #5
          Re: Tuple assignment and generators?

          In article <0KydnWcEJaVCtc fZnZ2dnUVZ_tmdn Z2d@comcast.com >,
          Larry Bates <larry.bates@we bsafe.com> wrote:
          [color=blue]
          > While I have never needed anything like this in my 5 years of Python
          > programming, here is a way:
          >
          > a,b,c = 3*[0]
          > q,r,s,t,u,v = 6*[0][/color]

          This is (IMO) fairly idiomatic:

          a = b = c = 0
          q = r = s = t = u = v = 0

          Just

          Comment

          • Larry Bates

            #6
            Re: Tuple assignment and generators?

            Just wrote:[color=blue]
            > In article <0KydnWcEJaVCtc fZnZ2dnUVZ_tmdn Z2d@comcast.com >,
            > Larry Bates <larry.bates@we bsafe.com> wrote:
            >[color=green]
            >> While I have never needed anything like this in my 5 years of Python
            >> programming, here is a way:
            >>
            >> a,b,c = 3*[0]
            >> q,r,s,t,u,v = 6*[0][/color]
            >
            > This is (IMO) fairly idiomatic:
            >
            > a = b = c = 0
            > q = r = s = t = u = v = 0
            >
            > Just[/color]

            You must be careful with this as they all point to
            exactly the same object. Example:
            [color=blue][color=green][color=darkred]
            >>> q = r = s = t = u = v = 0
            >>> id(q)[/color][/color][/color]
            3301924[color=blue][color=green][color=darkred]
            >>> id(r)[/color][/color][/color]
            3301924[color=blue][color=green][color=darkred]
            >>> id(s)[/color][/color][/color]
            3301924[color=blue][color=green][color=darkred]
            >>>[/color][/color][/color]

            Notice that all of them point to exactly the same object,
            not 6 copies of zero which is "probably" what the poster
            was thinking.

            Most of the time when I see this, it is because people are
            thinking of variables having values which is mostly a
            carry-over from old Fortran/Cobol/Basic programming ideas.
            In python variables are pointers to objects. Objects could
            be values, but they are not placeholders where you store
            stuff.

            I read on this list (quite frequently) that people
            think they are getting 6 separate variables each with
            a zero stored in them. They are not. They are getting
            six pointers that all point to an integer zero (IMHO it
            would be a rather odd application for a programmer
            to want this). Here is where multiple assignments
            causes problems for beginners:
            [color=blue][color=green][color=darkred]
            >>> a=[]
            >>> b=c=a
            >>> a.append(6)
            >>> b[/color][/color][/color]
            [6]

            What?? 'b' should contain an empty list, right? Nope.
            a, b, and c all point to the SAME list just like the
            poster's q, r, s, t, u, v all point to the SAME zero.

            What they meant to write was:

            c=a[:] # Shallow copy of list
            b=a[:]

            My rule, don't do it unless you know exactly why you
            want to do it. It will trip you up at some point and
            be VERY hard to find.

            -Larry Bates

            Comment

            • Tim Chase

              #7
              Re: Tuple assignment and generators?

              > I don't think he was explicitly wanting to initialize[color=blue]
              > things to zero, but rather unpack an arbitrary sequence
              > into a tuple (could perhaps be the fibonnacci sequence
              > for example).[/color]

              Ant is correct here...Fibonnac i, digits of pi, the constant
              42, an incrementing counter, a series of squares, whatever.
              That was my original intent in the matter. Zeros just
              happened to be a nice sort of place to start my exercise.
              [color=blue]
              > How about:
              >
              >[color=green][color=darkred]
              >>>>def zeros(count):[/color][/color]
              >
              > ... for i in range(count):
              > ... yield 0[/color]

              One of the things I was trying to avoid was having to know
              (and maintain) the count of items initialized. In the
              theoretical world of my example, one could do something like

              def counter():
              counter = 0
              while 1:
              yield counter
              counter += 1

              and then initialize several variables, such as
              [color=blue][color=green][color=darkred]
              >>> a,b,c,d,e,f,g = counter()
              >>> a,b,c,d,e,f,g[/color][/color][/color]
              (0,1,2,3,4,5,6)

              It's similar to C's auto-numbering of enum values...If I
              want to add another entry to a C enum, I just put it there,
              and let the language take care of matters. With most of the
              provided solutions, I also have to increment the count each
              time I add an item to the list.

              Diez provided an elegant solution with a decorator
              (employing an incredibly ugly sort of hack involving
              sniffing the opcode stack behind the scenes) that does what
              I was looking for.

              I was hoping that there was just some __foo__ property I was
              missing that would have been called in the process of tuple
              unpacking that would allow for a more elegant solution such
              as a generator (or generator method on some object) rather
              than stooping to disassembling opcodes. :)

              Ah well.

              -tkc




              Comment

              • jemfinch@gmail.com

                #8
                Re: Tuple assignment and generators?


                Larry Bates wrote:[color=blue]
                > Just wrote:[color=green]
                > > In article <0KydnWcEJaVCtc fZnZ2dnUVZ_tmdn Z2d@comcast.com >,
                > > Larry Bates <larry.bates@we bsafe.com> wrote:
                > >[color=darkred]
                > >> While I have never needed anything like this in my 5 years of Python
                > >> programming, here is a way:
                > >>
                > >> a,b,c = 3*[0]
                > >> q,r,s,t,u,v = 6*[0][/color]
                > >
                > > This is (IMO) fairly idiomatic:
                > >
                > > a = b = c = 0
                > > q = r = s = t = u = v = 0
                > >
                > > Just[/color]
                >
                > You must be careful with this as they all point to
                > exactly the same object. Example:
                >[color=green][color=darkred]
                > >>> q = r = s = t = u = v = 0
                > >>> id(q)[/color][/color]
                > 3301924[color=green][color=darkred]
                > >>> id(r)[/color][/color]
                > 3301924[color=green][color=darkred]
                > >>> id(s)[/color][/color]
                > 3301924[color=green][color=darkred]
                > >>>[/color][/color]
                >
                > Notice that all of them point to exactly the same object,
                > not 6 copies of zero which is "probably" what the poster
                > was thinking.[/color]

                Numbers are immutable. They're never copied. Zero, in particular, is
                the same variable all throughout a Python interpreter.
                [color=blue]
                > Most of the time when I see this, it is because people are
                > thinking of variables having values which is mostly a
                > carry-over from old Fortran/Cobol/Basic programming ideas.[/color]

                Most of the time when I see it, it's written by someone who's used
                Python for quite some time. It's a standard Python idiom. You'll find
                it all over the standard library. It's not a carry-over from
                Fortran/Cobol/Basic at all.
                [color=blue]
                > In python variables are pointers to objects. Objects could
                > be values, but they are not placeholders where you store
                > stuff.[/color]

                And all immutable objects are indistinguishab le from values. Immutable
                objects include ints, longs, strings, unicode objects, tuples,
                frozensets, and perhaps some others that I'm forgetting.
                [color=blue]
                > I read on this list (quite frequently) that people
                > think they are getting 6 separate variables each with
                > a zero stored in them.[/color]

                That's because they are. They're getting 6 different pointers
                (bindings) to zero. If you change one, the others remain pointed at
                (bound to) zero.
                [color=blue]
                > They are not. They are getting
                > six pointers that all point to an integer zero[/color]

                Six *different* pointers. Six *different* bindings.
                [color=blue]
                > (IMHO it
                > would be a rather odd application for a programmer
                > to want this).[/color]

                No, it wouldn't be. It's exactly how a person works with immutable
                (value) objects.
                [color=blue]
                > Here is where multiple assignments
                > causes problems for beginners:
                >[color=green][color=darkred]
                > >>> a=[]
                > >>> b=c=a
                > >>> a.append(6)
                > >>> b[/color][/color]
                > [6][/color]

                Yes, that does sometimes trouble beginners to programming. But so do
                regular expressions. Programmers ought not to restrict themselves by
                what beginners will have no difficulty learning.
                [color=blue]
                > What?? 'b' should contain an empty list, right? Nope.
                > a, b, and c all point to the SAME list just like the
                > poster's q, r, s, t, u, v all point to the SAME zero.[/color]

                There is only one zero in Python! It can never change!
                [color=blue]
                > What they meant to write was:
                >
                > c=a[:] # Shallow copy of list
                > b=a[:]
                >
                > My rule, don't do it unless you know exactly why you
                > want to do it. It will trip you up at some point and
                > be VERY hard to find.[/color]

                Your rule should only be followed by people who obstinately refuse
                either to understand the way variable bindings work in Python, or by
                people who refuse to know or care whether a given kind of object is
                immutable. And that group of people doesn't seem to include any of the
                good Python programmers I know.

                Jeremy

                Comment

                • jemfinch@gmail.com

                  #9
                  Re: Tuple assignment and generators?

                  > Zero, in particular, is the same variable all throughout a Python interpreter.

                  For the sake of accuracy let me note that I ought to have said, "is the
                  same *value* all throughout a Python interpreter."

                  Jeremy

                  Comment

                  • Ben Finney

                    #10
                    Re: Tuple assignment and generators?

                    jemfinch@gmail. com writes:
                    [color=blue]
                    > There is only one zero in Python! It can never change![/color]

                    +0.5 QOTW

                    --
                    \ "Madness is rare in individuals, but in groups, parties, |
                    `\ nations and ages it is the rule." -- Friedrich Nietzsche |
                    _o__) |
                    Ben Finney

                    Comment

                    • Carl Banks

                      #11
                      Re: Tuple assignment and generators?


                      Larry Bates wrote:[color=blue]
                      > You must be careful with this as they all point to
                      > exactly the same object. Example:
                      >[color=green][color=darkred]
                      > >>> q = r = s = t = u = v = 0
                      > >>> id(q)[/color][/color]
                      > 3301924[color=green][color=darkred]
                      > >>> id(r)[/color][/color]
                      > 3301924[color=green][color=darkred]
                      > >>> id(s)[/color][/color]
                      > 3301924[/color]

                      But:
                      [color=blue][color=green][color=darkred]
                      >>> q = 0
                      >>> r = 0
                      >>> s = 0
                      >>> id(q)[/color][/color][/color]
                      134536636[color=blue][color=green][color=darkred]
                      >>> id(r)[/color][/color][/color]
                      134536636[color=blue][color=green][color=darkred]
                      >>> id(s)[/color][/color][/color]
                      134536636


                      [snip][color=blue]
                      > My rule, don't do it unless you know exactly why you
                      > want to do it. It will trip you up at some point and
                      > be VERY hard to find.[/color]

                      It's ok to do it with constant objects, really.


                      Carl Banks

                      Comment

                      • Michele Simionato

                        #12
                        Re: Tuple assignment and generators?

                        Carl Banks wrote:[color=blue][color=green][color=darkred]
                        >>> q = 0
                        > >>> r = 0
                        > >>> s = 0
                        > >>> id(q)[/color][/color]
                        > 134536636[color=green][color=darkred]
                        > >>> id(r)[/color][/color]
                        > 134536636[color=green][color=darkred]
                        > >>> id(s)[/color][/color]
                        > 134536636
                        >[/color]
                        [color=blue]
                        > It is okay with constant object, really.[/color]

                        No:
                        [color=blue][color=green][color=darkred]
                        >>> r=100001
                        >>> s=100001
                        >>> t=100001
                        >>> id(r)[/color][/color][/color]
                        135620508[color=blue][color=green][color=darkred]
                        >>> id(s)[/color][/color][/color]
                        135620532[color=blue][color=green][color=darkred]
                        >>> id(t)[/color][/color][/color]
                        135104688

                        It worked with the number 0 because of an implementation accident,
                        in general Python can use different ids for constant objects that are
                        equals in the == sense.

                        Michele Simionato

                        Comment

                        • vdrab

                          #13
                          Re: Tuple assignment and generators?

                          Wow, so, to see if I understand correctly:
                          [color=blue][color=green][color=darkred]
                          >>> r = 0
                          >>> s = 0
                          >>> t = 100001
                          >>> u = 100001
                          >>> r == s[/color][/color][/color]
                          True[color=blue][color=green][color=darkred]
                          >>> t == u[/color][/color][/color]
                          True[color=blue][color=green][color=darkred]
                          >>> r is s[/color][/color][/color]
                          True[color=blue][color=green][color=darkred]
                          >>> t is u[/color][/color][/color]
                          False[color=blue][color=green][color=darkred]
                          >>> ... ?[/color][/color][/color]

                          what the...?
                          does anybody else get mighty uncomfortable about this?
                          s.

                          Comment

                          • Erik Max Francis

                            #14
                            Re: Tuple assignment and generators?

                            vdrab wrote:
                            [color=blue]
                            > what the...?
                            > does anybody else get mighty uncomfortable about this?[/color]

                            No. Why should you ever care about whether two integers representing
                            values are the same object? Your tests should be with `==`, not `is`.

                            --
                            Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
                            San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
                            More fodder for the new lost generation
                            -- Nik Kershaw

                            Comment

                            • Diez B. Roggisch

                              #15
                              Re: Tuple assignment and generators?

                              vdrab wrote:
                              [color=blue]
                              > Wow, so, to see if I understand correctly:
                              >[color=green][color=darkred]
                              >>>> r = 0
                              >>>> s = 0
                              >>>> t = 100001
                              >>>> u = 100001
                              >>>> r == s[/color][/color]
                              > True[color=green][color=darkred]
                              >>>> t == u[/color][/color]
                              > True[color=green][color=darkred]
                              >>>> r is s[/color][/color]
                              > True[color=green][color=darkred]
                              >>>> t is u[/color][/color]
                              > False[color=green][color=darkred]
                              >>>> ... ?[/color][/color]
                              >
                              > what the...?
                              > does anybody else get mighty uncomfortable about this?[/color]

                              #include <stdio.h>

                              int main(int argc, char **argv) {
                              int a = 1;
                              int b = 1;
                              printf("a == b: %i\n", a == b);
                              printf("&a == &b: %i\n", &a == &b);
                              return 0;
                              }

                              droggisch@ganes ha:/tmp$ ./test
                              a == b: 1
                              &a == &b: 0


                              Feeling the same might uncomfortablene ss? Get used to it: object identity
                              and two objects being part of an equality-relation are two different
                              beasts. It can get even worse: I can define an object (in C++ as well as in
                              python) that is not even equal to itself. Not that I felt the need for that
                              so far....

                              So: don't use object identity where you want equality. In all languages.

                              Diez

                              Comment

                              Working...