def a((b,c,d),e):

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

    def a((b,c,d),e):

    Fellow Pythonistas,

    Please check out

    Here's one to file in the "cryptic documentation" category. >>> import inspect >>> help(inspect.getargspec) Help on function getargspec in...


    if you haven't done so yet. It appears that you can specify a function
    explicitly to take n-tuples as arguments. It actually works, checked
    this myself. If you read the reference manual at

    really carefully, you will find that it is indeed part of the language
    spec, but it's a likely candidate for the least advertised Python
    feature. Small wonder since it looks like one of those language
    features that make committing atrocities an order of magnitude easier.

    Has anyone actually used it in real code?

    Cheers,

    AdSR

  • Simon Percivall

    #2
    Re: def a((b,c,d),e):

    You can always unpack a tuple that way, like in:

    ..>>> import sys
    ..>>> for (index, (key, value)) in enumerate(sys.m odules.iteritem s()):
    pass

    Comment

    • Michael Spencer

      #3
      Re: def a((b,c,d),e):

      AdSR wrote:[color=blue]
      > Fellow Pythonistas,
      >
      > Please check out
      >
      > http://spyced.blogspot.com/2005/04/h...on-part-3.html
      >
      > if you haven't done so yet. It appears that you can specify a function
      > explicitly to take n-tuples as arguments. It actually works, checked
      > this myself. If you read the reference manual at
      > http://docs.python.org/ref/function.html
      > really carefully, you will find that it is indeed part of the language
      > spec, but it's a likely candidate for the least advertised Python
      > feature.
      >[/color]
      See also the source of inspect.getargs for just how much this complicates the
      argument-passing logic!
      [color=blue]
      > Small wonder since it looks like one of those language
      > features that make committing atrocities an order of magnitude easier.
      >
      > Has anyone actually used it in real code?[/color]

      It appears in a handful of places in the stdlib, mostly tests:
      #Search C:\Python23\Lib
      # Files *.py
      # For def [\w]+\(\(
      c:\python23\lib \test\test_comp ile.py(49) def comp_args((a, b)):
      c:\python23\lib \test\test_comp ile.py(53) def comp_args((a, b)=(3, 4)):
      c:\python23\lib \test\test_gram mar.py(159) def f5((compound, first), two): pass
      c:\python23\lib \test\test_scop e.py(318) def makeAddPair((a, b)):
      c:\python23\lib \test\test_scop e.py(319) def addPair((c, d)):
      c:\python23\lib \site-packages\wx-2.5.3-msw-ansi\wx\lib\ima geutils.py(36) def
      makeGray((r,g,b ), factor, maskColor):
      c:\python23\lib \cgitb.py(82) def html((etype, evalue, etb), context=5):
      c:\python23\lib \cgitb.py(168) def text((etype, evalue, etb), context=5):
      c:\python23\lib \urlparse.py(11 8) def urlunparse((sch eme, netloc, url, params,
      query, fragment)):
      c:\python23\lib \urlparse.py(12 7) def urlunsplit((sch eme, netloc, url, query,
      fragment)):
      [color=blue]
      >
      > Cheers,
      >
      > AdSR[/color]

      Comment

      • Fredrik Lundh

        #4
        Re: def a((b,c,d),e):

        "AdSR" <artur_spruce@y ahoo.com> wrote:
        [color=blue]
        > Small wonder since it looks like one of those language features
        > that make committing atrocities an order of magnitude easier.[/color]

        eh?

        def f((a, b)):
        ...

        is short for

        def f(tmp):
        a, b = tmp
        ...

        if you think this is an "atrocity", maybe programming isn't for you.
        [color=blue]
        > Has anyone actually used it in real code?[/color]

        yes. grep the standard library for a number of typical use cases.

        </F>

        Comment

        • Fredrik Lundh

          #5
          Re: def a((b,c,d),e):

          Michael Spencer wrote:
          [color=blue]
          > See also the source of inspect.getargs for just how much this complicates the
          > argument-passing logic![/color]

          it doesn't complicate the argument-passing in any way at all -- it complicates
          the reverse engineering code a bit, though, since it has to convert the bytecode
          for

          def f(tmp):
          a, b = tmp
          ...

          back to the original source form

          def f((a, b)):
          ...

          but that has absolutely nothing whatsoever to do with how argument passing
          works at run time.

          </F>

          Comment

          • AdSR

            #6
            Re: def a((b,c,d),e):

            > if you think this is an "atrocity", maybe programming isn't for you.

            My resume might suggest otherwise but I guess that's not the main topic
            here. Maybe I got carried away -- this one took me completely by
            surprise.

            Anyway, this gets interesting:

            def z(((a, b), (c, d)), (e, f)):
            pass

            although I see that it could be perfectly valid in some contexts.

            Cheers,

            AdSR

            Comment

            • Diez B. Roggisch

              #7
              Re: def a((b,c,d),e):

              AdSR wrote:
              [color=blue]
              > Fellow Pythonistas,
              >
              > Please check out
              >
              > http://spyced.blogspot.com/2005/04/h...on-part-3.html
              >
              > if you haven't done so yet. It appears that you can specify a function
              > explicitly to take n-tuples as arguments. It actually works, checked
              > this myself. If you read the reference manual at
              > http://docs.python.org/ref/function.html
              > really carefully, you will find that it is indeed part of the language
              > spec, but it's a likely candidate for the least advertised Python
              > feature. Small wonder since it looks like one of those language
              > features that make committing atrocities an order of magnitude easier.
              >
              > Has anyone actually used it in real code?[/color]

              Yes, but usually not so much in function arguments but more in
              list-comprehensions or other places where unpacking was useful. I love the
              feature - I just don't have nested enough data to use it more :)

              What python offers in this respect can be seen as a limited form of
              pattern-matching known from functional programming - and instead of beeing
              considered an atrocity it's actually frequently requested to be enhanced.

              --
              Regards,

              Diez B. Roggisch

              Comment

              • AdSR

                #8
                Re: def a((b,c,d),e):

                > Yes, but usually not so much in function arguments but more in[color=blue]
                > list-comprehensions or other places where unpacking was useful. I[/color]
                love the[color=blue]
                > feature - I just don't have nested enough data to use it more :)[/color]

                I use tuple unpacking in its typical uses, it's one of the first
                language features I learned about. Somehow it never occurred to me that
                you could use it in function arguments this way - I only knew f(*args,
                **kwargs) style in this context. That's what I made the whole fuss
                about...

                AdSR

                Comment

                • François Pinard

                  #9
                  Re: def a((b,c,d),e):

                  [Diez B. Roggisch][color=blue]
                  > AdSR wrote:[/color]
                  [color=blue][color=green]
                  > > It appears that you can specify a function explicitly to take
                  > > n-tuples as arguments. [...] Has anyone actually used it in real
                  > > code?[/color][/color]

                  I do not use it often in practice, but sometimes, yes. If the feature
                  was not there, it would be easy to do an explicit tuple unpacking from
                  the argument at the start of the function. It allows me to spare
                  inventing a name for the compound formal argument. :-)
                  [color=blue]
                  > [...] as a limited form of pattern-matching [...][/color]

                  In one application, written long ago, I had a flurry of functions
                  kept in a list, which were tried in turn until the call does not
                  raise an Exception, so indicating a match. Since then, I used other
                  means, first hoping to save at least the time it takes for creating a
                  traceback object (but I did not time it), and later trying to get a
                  better-than-linear time while trying to find the correct function.

                  I never considered the feature to be atrocious. Implicit tuple
                  unpacking occurs in a few places in Python already, it is only elegant
                  that it also occurs while functions receive their argument. The most
                  useful place for implicit tuple unpacking, in my experience, is likely
                  at the left of the `in' keyword in `for' statements (and it is even
                  nicer when one avoids extraneous parentheses).

                  --
                  François Pinard http://pinard.progiciels-bpi.ca

                  Comment

                  • John Machin

                    #10
                    Re: def a((b,c,d),e):

                    On 18 Apr 2005 13:05:57 -0700, "AdSR" <artur_spruce@y ahoo.com> wrote:
                    [color=blue]
                    >Fellow Pythonistas,
                    >
                    >Please check out
                    >
                    >http://spyced.blogspot.com/2005/04/h...on-part-3.html
                    >
                    >if you haven't done so yet. It appears that you can specify a function
                    >explicitly to take n-tuples as arguments. It actually works, checked
                    >this myself. If you read the reference manual at
                    >http://docs.python.org/ref/function.html
                    >really carefully, you will find that it is indeed part of the language
                    >spec, but it's a likely candidate for the least advertised Python
                    >feature. Small wonder since it looks like one of those language
                    >features that make committing atrocities an order of magnitude easier.
                    >[/color]

                    Thanks for pointing this out. However I see no atrocity potential here
                    -- what did you have in mind?

                    See below. Better documentation in the "def" (even better than having
                    say "year_month_day " instead of my lazy "dt_tup"). No overhead;
                    byte-code is the same.
                    [color=blue][color=green][color=darkred]
                    >>> def weird_date_from _tuple(dt_tup):[/color][/color][/color]
                    .... year, month, day = dt_tup
                    .... return
                    ....[color=blue][color=green][color=darkred]
                    >>> import dis
                    >>> dis.dis(weird_d ate_from_tuple)[/color][/color][/color]
                    2 0 LOAD_FAST 0 (dt_tup)
                    3 UNPACK_SEQUENCE 3
                    6 STORE_FAST 3 (year)
                    9 STORE_FAST 1 (month)
                    12 STORE_FAST 2 (day)

                    3 15 LOAD_CONST 0 (None)
                    18 RETURN_VALUE[color=blue][color=green][color=darkred]
                    >>> def weird_date_from _tuple((year, month, day)):[/color][/color][/color]
                    .... return
                    ....[color=blue][color=green][color=darkred]
                    >>> dis.dis(weird_d ate_from_tuple)[/color][/color][/color]
                    1 0 LOAD_FAST 0 (.0)
                    3 UNPACK_SEQUENCE 3
                    6 STORE_FAST 1 (year)
                    9 STORE_FAST 2 (month)
                    12 STORE_FAST 3 (day)

                    2 15 LOAD_CONST 0 (None)
                    18 RETURN_VALUE[color=blue][color=green][color=darkred]
                    >>>[/color][/color][/color]

                    Cheers,
                    John


                    Comment

                    • Diez B. Roggisch

                      #11
                      Re: def a((b,c,d),e):

                      AdSR wrote:
                      [color=blue][color=green]
                      >> Yes, but usually not so much in function arguments but more in
                      >> list-comprehensions or other places where unpacking was useful. I[/color]
                      > love the[color=green]
                      >> feature - I just don't have nested enough data to use it more :)[/color]
                      >
                      > I use tuple unpacking in its typical uses, it's one of the first
                      > language features I learned about. Somehow it never occurred to me that
                      > you could use it in function arguments this way - I only knew f(*args,
                      > **kwargs) style in this context. That's what I made the whole fuss
                      > about...[/color]

                      Well, if you think about it the whole positional argument passing is nothing
                      more than tuple unpacking. Its like having an anonymous variable that gets
                      unpacked:

                      def foo(a,b,c = i_m_so_anonymou s):
                      pass


                      So it's just orthogonal to have the full functionality of unpacking
                      available for function arguments - including the nested tuples.

                      --
                      Regards,

                      Diez B. Roggisch

                      Comment

                      • AdSR

                        #12
                        Re: def a((b,c,d),e):

                        > Thanks for pointing this out. However I see no atrocity potential
                        here[color=blue]
                        > -- what did you have in mind?[/color]

                        Bad choice of words. I meant obfuscated, something like

                        def z(((a, b), (c, d)), e, f):
                        pass

                        but much worse. But it looks like there is nothing unusual about it
                        after all. Oh, well...

                        AdSR

                        Comment

                        • George Sakkis

                          #13
                          Re: def a((b,c,d),e):

                          François Pinard wrote:
                          [color=blue]
                          > The most useful place for implicit tuple unpacking, in my experience,
                          > is likely at the left of the `in' keyword in `for' statements (and
                          > it is even nicer when one avoids extraneous parentheses).[/color]

                          .... and would be nicest (IMO) if default arguments and *varargs were
                          allowed too; check http://tinyurl.com/dcb2q for a relevant thread.

                          George

                          Comment

                          • François Pinard

                            #14
                            Re: def a((b,c,d),e):

                            [George Sakkis][color=blue]
                            > François Pinard wrote:[/color]
                            [color=blue][color=green]
                            > > The most useful place for implicit tuple unpacking, in my
                            > > experience, is likely at the left of the `in' keyword in `for'
                            > > statements (and it is even nicer when one avoids extraneous
                            > > parentheses).[/color][/color]
                            [color=blue]
                            > ... and would be nicest (IMO) if default arguments and *varargs were
                            > allowed too; check http://tinyurl.com/dcb2q for a relevant thread.[/color]

                            It's appealing, indeed, trying to create more uniformity between tuple
                            unpacking and argument passing. There are two approaches towards such
                            uniformity, either upgrading tuple unpacking (as the above thread
                            discusses) or downgrading argument passing (as suggested by those who
                            found atrocious the current behaviour).

                            I started recently to study the R system and language, and saw many good
                            ideas in there about argument passing. Translated in Python terms, it
                            would mean that `*varargs' and `**keywords' are not necessary last,
                            that named keywords may be intermixed with positional keywords, that
                            keywords may be abbreviated, and much more hairy, that the default
                            values for keywords are not pre-evaluated at `def' time, and that
                            the computation of actual expressions given as arguments is lazily
                            postponed until their first use within the function. It surely looks
                            all strange at first, but these choices are surprisingly productive in
                            practice, as I merely begin to understand. Curious minds may start at
                            http://cran.r-project.org/doc/manual...html#Arguments and read
                            down. I do not know if there will ever be cross-pollinisation between R
                            and Python, but I would guess good things might came out of this...

                            --
                            François Pinard http://pinard.progiciels-bpi.ca

                            Comment

                            • George Sakkis

                              #15
                              Re: def a((b,c,d),e):

                              "François Pinard" wrote:[color=blue]
                              >
                              > I started recently to study the R system and language, and saw many[/color]
                              good[color=blue]
                              > ideas in there about argument passing. Translated in Python terms,[/color]
                              it[color=blue]
                              > would mean that `*varargs' and `**keywords' are not necessary last,
                              > that named keywords may be intermixed with positional keywords, that[/color]

                              This would be neat indeed. Occasionally I come across situations where
                              I wished to be able to specify default arguments after positional, as
                              for example in "def accumulate(*ite ms, default=0)". The current
                              possible workarounds are:
                              - pass an iterable instead of positional arguments: "def
                              accumulate(item s, default=0)". This is not always elegant, especially
                              if the function is called with few independently derived items (as
                              opposed, for example, to items derived by a list/generator
                              comprehension, which is already an iterable).
                              - pass named keywords instead of default: "def accumulate(*ite ms,
                              **kwds)". I tend to think of **kwds as a nice feature for functions
                              with almost open-ended functionality, that intend to be extended in the
                              future with more customization options. In more typical cases though of
                              a function with one or two defaults, using **kwds obscures the
                              function's signature without a visible benefit. Also, I'm not sure of
                              the efficiency penalty imposed by constructing and passing a dict of
                              length 1 or 2 instead of default arguments.
                              - Put the default(s) before the positional arguments: "def
                              accumulate(defa ult=0, *items)". This practically negates the purpose of
                              using defaults in the first place since the first passed argument is
                              bounded to default.

                              Allowing non-default arguments after *varargs doesn't make sense, but
                              it does for default arguments. The parameter binding rule would just
                              need to be augmented so that default parameter arguments after *varargs
                              would be bounded to their default value unless specified explicitly in
                              the call as named arguments:
                              accumulate(1,2) == accumulate(1,2 default=0) and
                              accumulate([1],[2],default=[]) == accumulate([1],default=[], [2]) ==
                              accumulate(defa ult=[], [1], [2])
                              [color=blue]
                              > keywords may be abbreviated, and much more hairy,[/color]

                              Hmm.. -1 on this. It may save a few keystrokes, but it's not good for
                              readability and maintenability.
                              [color=blue]
                              > that the default
                              > values for keywords are not pre-evaluated at `def' time, and that[/color]


                              Definitely a +1 on this. I've always seen pre-evaluation as a wart,
                              especially with respect to mutable default values. If some sort of
                              state needs to be preserved between calls, the right way is to
                              encapsulate it in class, not in a default value.
                              [color=blue]
                              > the computation of actual expressions given as arguments is lazily
                              > postponed until their first use within the function.[/color]

                              Is this like an implicit lambda before each argument ? If so, why does
                              it have to be restricted to function arguments ? It seems to me that
                              argument passing and lazy evaluation are orthogonal dimensions. Let's
                              keep the "should python become lazy ?" question for a future thread :-)

                              Concerning default argument expressions, a neat feature would be to
                              allow an expression to refer to other arguments, as in "def
                              foo(a,b,s=a+b)" instead of the current workaround which goes like:
                              def foo(a,b,s=None) :
                              if s is None: s = a+b
                              Or for a more exotic use:
                              def prologLikeSum(a =s-b, b=s-a, s=a+b):
                              return a,b,s
                              prologLikeSum(1 ,2) == prologLikeSum(1 ,s=3) == prologLikeSum(b =2,s=3) ==
                              (1,2,3)

                              This seems pretty hard to change though. For one thing, it would
                              require new syntax to denote which names in the expression refer to
                              other arguments instead of the enclosing scope. Also the binding of
                              arguments to values would no more be considered "parallel"; the order
                              of the bindings would be significant, and even worse, it would have to
                              be computed for each call, as the prologLikeSum example shows.

                              Probably-I'm-just-rambling-ly yrs
                              George

                              Comment

                              Working...