forwarding *arg parameter

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

    #1

    forwarding *arg parameter

    >>def g(*arg):
    .... return arg
    ....
    >>g('foo', 'bar')
    ('foo', 'bar')
    >># seems reasonable
    ....
    >>g(g('foo', 'bar'))
    (('foo', 'bar'),)
    >># not so good, what g should return to get rid of the outer tuple
    TV
  • Diez B. Roggisch

    #2
    Re: forwarding *arg parameter

    Tuomas schrieb:
    >>def g(*arg):
    ... return arg
    ...
    >>g('foo', 'bar')
    ('foo', 'bar')
    >># seems reasonable
    ...
    >>g(g('foo', 'bar'))
    (('foo', 'bar'),)
    >># not so good, what g should return to get rid of the outer tuple
    g(*g('foo', 'bar'))


    * and ** are the symetric - they capture ellipsis arguments, and they
    make iterables/dicts passed as positional/named arguments.

    Diez

    Comment

    • Tuomas

      #3
      Re: forwarding *arg parameter

      Diez B. Roggisch wrote:
      Tuomas schrieb:
      >
      > >>def g(*arg):
      >... return arg
      >...
      > >>g('foo', 'bar')
      >('foo', 'bar')
      > >># seems reasonable
      >...
      > >>g(g('foo', 'bar'))
      >(('foo', 'bar'),)
      > >># not so good, what g should return to get rid of the outer tuple
      >
      >
      g(*g('foo', 'bar'))
      >
      >
      * and ** are the symetric - they capture ellipsis arguments, and they
      make iterables/dicts passed as positional/named arguments.
      >
      Diez
      Thanks Diez

      And what about this case if I want the result ('foo', 'bar')
      >>def f(*arg):
      .... return g(arg)
      ....
      >>f('foo', 'bar')
      (('foo', 'bar'),)
      >>def h(*arg):
      .... return arg[0]
      ....
      >>g=h
      >>f('foo', 'bar')
      ('foo', 'bar')

      Where can g know it should use arg[0] when arg is forwarded?

      TV

      Comment

      • Stargaming

        #4
        Re: forwarding *arg parameter

        Tuomas schrieb:
        >>def g(*arg):
        ... return arg
        ...
        >>g('foo', 'bar')
        ('foo', 'bar')
        >># seems reasonable
        ...
        >>g(g('foo', 'bar'))
        (('foo', 'bar'),)
        >># not so good, what g should return to get rid of the outer tuple
        >
        TV
        Use the following then:
        >>g(*g('foo', 'bar'))
        ('foo', 'bar')

        Otherwise, you would have to check if arg is a 1-tuple consisting of a
        tuple and "strip" it out then.

        e.g.
        >>def g(*arg):
        .... return arg[0] if isinstance(arg[0], tuple) else arg
        ....
        >>g('foo', 'bar')
        ('foo', 'bar')
        >>g(g('foo', 'bar'))
        ('foo', 'bar')

        Comment

        • Steven D'Aprano

          #5
          Re: forwarding *arg parameter

          On Sun, 05 Nov 2006 15:26:58 +0000, Tuomas wrote:
          >>def g(*arg):
          ... return arg
          ...
          >>g('foo', 'bar')
          ('foo', 'bar')
          >># seems reasonable
          The function g:
          - takes the arguments 'foo' and 'bar'
          - collects them in a tuple named 'arg' = ('foo', 'bar')
          - returns the tuple named arg

          >>g(g('foo', 'bar'))
          (('foo', 'bar'),)
          The function g:
          - takes the argument ('foo', 'bar')
          - collects it in a tuple named 'arg' = (('foo', 'bar'),)
          - returns the tuple named arg

          The function is doing exactly the same as in the first case, except the
          arguments are different.

          >># not so good, what g should return to get rid of the outer tuple
          Why do you want to? The way the function is now makes perfect sense. All
          argument types are treated in exactly the same way:

          g(string) =tuple containing string
          g(float) =tuple containing float
          g(int) =tuple containing int
          g(list) =tuple containing list
          g(instance) =tuple containing instance
          g(tuple) =tuple containing tuple

          You could write something like this:

          def g(*arg):
          # Detect the special case of a single tuple argument
          if len(arg) == 1 and type(arg[0]) == tuple:
          return arg[0]
          else:
          return arg

          but now tuple arguments are treated differently to all other data. Why do
          you think you need that?


          --
          Steven

          Comment

          • Tuomas

            #6
            Re: forwarding *arg parameter

            Steven D'Aprano wrote:
            <snip>
            You could write something like this:
            >
            def g(*arg):
            # Detect the special case of a single tuple argument
            if len(arg) == 1 and type(arg[0]) == tuple:
            return arg[0]
            else:
            return arg
            >
            but now tuple arguments are treated differently to all other data. Why do
            you think you need that?
            I am looking a shorter way to do the above in the case:

            def g(*arg):
            return arg

            def f(*arg):
            return g(arg)

            How can g know if it is called directly with (('foo', 'bar'),) or via f
            with ('foo', 'bar'). I coud write in f: return g(arg[0], arg[1]) if I
            know the number of arguments, but what if I don't know that in design time?

            TV

            Comment

            • Tuomas

              #7
              Re: forwarding *arg parameter

              Tuomas wrote:
              def g(*arg):
              return arg
              >
              def f(*arg):
              return g(arg)
              >
              How can g know if it is called directly with (('foo', 'bar'),) or via f
              with ('foo', 'bar'). I coud write in f: return g(arg[0], arg[1]) if I
              know the number of arguments, but what if I don't know that in design time?
              So it seems that I would like to have an unpack operator:

              def f(*arg):
              return(!*arg)

              TV

              Comment

              • Stargaming

                #8
                Re: forwarding *arg parameter

                Tuomas schrieb:
                Tuomas wrote:
                >
                >def g(*arg):
                > return arg
                >>
                >def f(*arg):
                > return g(arg)
                >>
                >How can g know if it is called directly with (('foo', 'bar'),) or via
                >f with ('foo', 'bar'). I coud write in f: return g(arg[0], arg[1]) if
                >I know the number of arguments, but what if I don't know that in
                >design time?
                >
                >
                So it seems that I would like to have an unpack operator:
                >
                def f(*arg):
                return(!*arg)
                >
                TV
                Either you take one of the snippets here:

                or just use arg[0] clever (as mentioned a few times in this thread).

                Comment

                • Tuomas

                  #9
                  Re: forwarding *arg parameter

                  Stargaming wrote:
                  Either you take one of the snippets here:

                  >
                  or just use arg[0] clever (as mentioned a few times in this thread).
                  Thanks. My solution became:
                  >>def flattern(arg):
                  .... result = []
                  .... for item in arg:
                  .... if isinstance(item , (list, tuple)):
                  .... result.extend(f lattern(item))
                  .... else:
                  .... result.append(i tem)
                  .... return tuple(result)
                  ....
                  >>def g(*arg):
                  .... arg = flattern(arg)
                  .... return arg
                  ....
                  >>def f(*arg):
                  .... return g(arg)
                  ....
                  >>f('foo', 'bar')
                  ('foo', 'bar')

                  TV

                  Comment

                  • Tuomas

                    #10
                    Re: forwarding *arg parameter

                    Dennis Lee Bieber wrote:
                    On Sun, 05 Nov 2006 17:42:30 GMT, Tuomas <tuomas.vesteri nen@pp.inet.fi>
                    declaimed the following in comp.lang.pytho n:
                    >
                    >
                    >
                    >>I am looking a shorter way to do the above in the case:
                    >>
                    >>def g(*arg):
                    > return arg
                    >>
                    >>def f(*arg):
                    > return g(arg)
                    >>
                    >>How can g know if it is called directly with (('foo', 'bar'),) or via f
                    >
                    >
                    Typically, the responsibility should be on the CALLER, not the
                    CALLED..
                    >
                    >
                    >>>>def g(*arg):
                    >
                    ... return arg
                    ...
                    >
                    >>>>def f(*arg):
                    >
                    ... return g(*arg) #<<<<<<<< unpack tuple on call
                    ...
                    >
                    >>>>f("a", 1, 2)
                    >
                    ('a', 1, 2)
                    >
                    >
                    Note how f() is calling g() using an * -- Since f() "knows" that its
                    arguments were "packed" it calls g() with an unpack marker. Then g()
                    gets the arguments via whatever scheme it was coded to use.
                    >
                    >
                    >>>>def f(*arg):
                    >
                    ... return g(arg) #<<<<<<<<<< no tuple unpack
                    ...
                    >
                    >>>>f("a", 1, 2)
                    >
                    (('a', 1, 2),)
                    >
                    >
                    I fylly agree with tis: "Typically, the responsibility should be on the
                    CALLER, not the CALLED..". I just don't know how to unpack *arg for
                    calling g. I can get the len(arg), but how to formulate an unpacked call
                    g(arg[0], arg[1], ..). Building a string for eval("g(arg[0], arg[1],
                    ...)") seems glumsy to me.

                    TV

                    Comment

                    • Steven D'Aprano

                      #11
                      Re: forwarding *arg parameter

                      On Sun, 05 Nov 2006 19:35:58 +0000, Tuomas wrote:
                      Thanks. My solution became:
                      >
                      >>def flattern(arg):
                      ... result = []
                      ... for item in arg:
                      ... if isinstance(item , (list, tuple)):
                      ... result.extend(f lattern(item))
                      ... else:
                      ... result.append(i tem)
                      ... return tuple(result)
                      ...
                      >>def g(*arg):
                      ... arg = flattern(arg)
                      ... return arg
                      ...
                      >>def f(*arg):
                      ... return g(arg)
                      ...
                      >>f('foo', 'bar')
                      ('foo', 'bar')

                      That's the most complicated do-nothing function I've ever seen. Here is a
                      shorter version:

                      def shortf(*args):
                      return args

                      >>f('foo', 'bar')
                      ('foo', 'bar')
                      >>shortf('foo ', 'bar')
                      ('foo', 'bar')
                      >>f(1,2,3,4)
                      (1, 2, 3, 4)
                      >>shortf(1,2,3, 4)
                      (1, 2, 3, 4)
                      >>f({}, None, 1, -1.2, "hello world")
                      ({}, None, 1, -1.2, 'hello world')
                      >>shortf({}, None, 1, -1.2, "hello world")
                      ({}, None, 1, -1.2, 'hello world')

                      Actually, they aren't *quite* identical: your function rips lists apart,
                      which is probably not a good idea.
                      >>f("foo", [1,2,3], None) # three arguments turns into five
                      ('foo', 1, 2, 3, None)
                      >>shortf("foo ", [1,2,3], None) # three arguments stays three
                      ('foo', [1, 2, 3], None)



                      I still don't understand why you are doing this. Can we have an example of
                      why you think you need to do this?



                      --
                      Steven.

                      Comment

                      • Tuomas

                        #12
                        Re: forwarding *arg parameter

                        Dennis Lee Bieber wrote:
                        On Sun, 05 Nov 2006 22:51:00 GMT, Tuomas <tuomas.vesteri nen@pp.inet.fi>
                        declaimed the following in comp.lang.pytho n:
                        >
                        >
                        >>>
                        >>
                        >>I fylly agree with tis: "Typically, the responsibility should be on the
                        >>CALLER, not the CALLED..". I just don't know how to unpack *arg for
                        >>calling g. I can get the len(arg), but how to formulate an unpacked call
                        >>g(arg[0], arg[1], ..). Building a string for eval("g(arg[0], arg[1],
                        >>..)") seems glumsy to me.
                        >>
                        >
                        Did you miss the example I gave? Using "*args" on the "def"
                        essentially says "pack remaining arguments into one tuple". Using
                        "*args" on a CALL says "UNPACK tuple into positional arguments"
                        >
                        def f(*args): <<<< pack arguments into tuple
                        Thats it:
                        x = g(*args) >>>unpack args tuple when calling
                        Yesterday I tested something like this and got a syntax error. So I got
                        misunderstandin g that "g(*args)" is'nt a proper syntax. Obviously my
                        test sentence had some other syntax error. Sorry.

                        TV

                        Comment

                        • Tuomas

                          #13
                          Re: forwarding *arg parameter

                          Steven D'Aprano wrote:
                          On Sun, 05 Nov 2006 19:35:58 +0000, Tuomas wrote:
                          >
                          >
                          >>Thanks. My solution became:
                          >>
                          >>def flattern(arg):
                          >>... result = []
                          >>... for item in arg:
                          >>... if isinstance(item , (list, tuple)):
                          >>... result.extend(f lattern(item))
                          >>... else:
                          >>... result.append(i tem)
                          >>... return tuple(result)
                          >>...
                          >>def g(*arg):
                          >>... arg = flattern(arg)
                          >>... return arg
                          >>...
                          >>def f(*arg):
                          >>... return g(arg)
                          >>...
                          >>f('foo', 'bar')
                          >>('foo', 'bar')
                          >
                          >
                          >
                          That's the most complicated do-nothing function I've ever seen. Here is a
                          shorter version:
                          >
                          def shortf(*args):
                          return args
                          >
                          >
                          >
                          >>>>f('foo', 'bar')
                          >
                          ('foo', 'bar')
                          >
                          >>>>shortf('foo ', 'bar')
                          >
                          ('foo', 'bar')
                          >
                          >
                          >>>>f(1,2,3,4 )
                          >
                          (1, 2, 3, 4)
                          >
                          >>>>shortf(1,2, 3,4)
                          >
                          (1, 2, 3, 4)
                          >
                          >
                          >>>>f({}, None, 1, -1.2, "hello world")
                          >
                          ({}, None, 1, -1.2, 'hello world')
                          >
                          >>>>shortf({} , None, 1, -1.2, "hello world")
                          >
                          ({}, None, 1, -1.2, 'hello world')
                          >
                          Actually, they aren't *quite* identical: your function rips lists apart,
                          which is probably not a good idea.
                          >
                          >
                          >>>>f("foo", [1,2,3], None) # three arguments turns into five
                          >
                          ('foo', 1, 2, 3, None)
                          >
                          >>>>shortf("foo ", [1,2,3], None) # three arguments stays three
                          >
                          ('foo', [1, 2, 3], None)
                          >
                          >
                          >
                          I still don't understand why you are doing this. Can we have an example of
                          why you think you need to do this?
                          If i redefine the function g the difference comes visible:
                          >>def g(*arg):
                          .... if with_flattern: arg=flattern(ar g)
                          .... return arg
                          >>with_flattern =False
                          >>f('foo', 'bar')
                          (('foo', 'bar'),)
                          >>with_flattern =True
                          >>f('foo', 'bar')
                          If you read the whole chain you find out what we were talking of.

                          TV

                          Comment

                          • Steve Holden

                            #14
                            Re: forwarding *arg parameter

                            Tuomas wrote:
                            Steven D'Aprano wrote:
                            >
                            >>On Sun, 05 Nov 2006 19:35:58 +0000, Tuomas wrote:
                            >>
                            >>
                            >>
                            >>>Thanks. My solution became:
                            >>>
                            >>>
                            >>>>>>def flattern(arg):
                            >>>
                            >>>... result = []
                            >>>... for item in arg:
                            >>>... if isinstance(item , (list, tuple)):
                            >>>... result.extend(f lattern(item))
                            >>>... else:
                            >>>... result.append(i tem)
                            >>>... return tuple(result)
                            >>>...
                            >>>
                            >>>>>>def g(*arg):
                            >>>
                            >>>... arg = flattern(arg)
                            >>>... return arg
                            >>>...
                            >>>
                            >>>>>>def f(*arg):
                            >>>
                            >>>... return g(arg)
                            >>>...
                            >>>
                            >>>>>>f('foo' , 'bar')
                            >>>
                            >>>('foo', 'bar')
                            >>
                            >>
                            >>
                            >>That's the most complicated do-nothing function I've ever seen. Here is a
                            >>shorter version:
                            >>
                            >>def shortf(*args):
                            > return args
                            >>
                            >>
                            >>
                            >>
                            >>>>>f('foo', 'bar')
                            >>
                            >>('foo', 'bar')
                            >>
                            >>
                            >>>>>shortf('fo o', 'bar')
                            >>
                            >>('foo', 'bar')
                            >>
                            >>
                            >>
                            >>>>>f(1,2,3, 4)
                            >>
                            >>(1, 2, 3, 4)
                            >>
                            >>
                            >>>>>shortf(1,2 ,3,4)
                            >>
                            >>(1, 2, 3, 4)
                            >>
                            >>
                            >>
                            >>>>>f({}, None, 1, -1.2, "hello world")
                            >>
                            >>({}, None, 1, -1.2, 'hello world')
                            >>
                            >>
                            >>>>>shortf({ }, None, 1, -1.2, "hello world")
                            >>
                            >>({}, None, 1, -1.2, 'hello world')
                            >>
                            >>Actually, they aren't *quite* identical: your function rips lists apart,
                            >>which is probably not a good idea.
                            >>
                            >>
                            >>
                            >>>>>f("foo", [1,2,3], None) # three arguments turns into five
                            >>
                            >>('foo', 1, 2, 3, None)
                            >>
                            >>
                            >>>>>shortf("fo o", [1,2,3], None) # three arguments stays three
                            >>
                            >>('foo', [1, 2, 3], None)
                            >>
                            >>
                            >>
                            >>I still don't understand why you are doing this. Can we have an example of
                            >>why you think you need to do this?
                            >
                            >
                            If i redefine the function g the difference comes visible:
                            >
                            >>def g(*arg):
                            .... if with_flattern: arg=flattern(ar g)
                            .... return arg
                            >
                            >>with_flattern =False
                            >>f('foo', 'bar')
                            (('foo', 'bar'),)
                            >>with_flattern =True
                            >>f('foo', 'bar')
                            >
                            If you read the whole chain you find out what we were talking of.
                            >
                            TV
                            Suppose you did actually want to do this you have chosen about the worst
                            possible way: the use of global variables to condition function
                            execution is a sure way to get into trouble. Consider if somebody else
                            want to use your function: they also have to set a global in their
                            program to avoid your function raising an exception.

                            Fortunately Python has just the thing to make such horrors unnecessary:
                            the default argument value. Try something like this (untested):

                            def g(flattening=Tr ue, *arg):
                            if flattening:
                            arg = flatten(arg)
                            return arg

                            Obviously you could use either True or False for the default value. In
                            the case above the function flattens by default. You could also, if you
                            wished, have f() take the flattening argument, and always pass it to g().

                            Nothing very sophisticated here, just something to help you flex your
                            growing Python and programming muscles.

                            regards
                            Steve
                            --
                            Steve Holden +44 150 684 7255 +1 800 494 3119
                            Holden Web LLC/Ltd http://www.holdenweb.com
                            Skype: holdenweb http://holdenweb.blogspot.com
                            Recent Ramblings http://del.icio.us/steve.holden

                            Comment

                            • Tuomas

                              #15
                              Re: forwarding *arg parameter

                              Steve Holden wrote:
                              Suppose you did actually want to do this you have chosen about the worst
                              possible way: the use of global variables to condition function
                              execution is a sure way to get into trouble. Consider if somebody else
                              want to use your function: they also have to set a global in their
                              program to avoid your function raising an exception.
                              Do you think all discussion examples are included a producton application.
                              Fortunately Python has just the thing to make such horrors unnecessary:
                              the default argument value. Try something like this (untested):
                              >
                              def g(flattening=Tr ue, *arg):
                              if flattening:
                              arg = flatten(arg)
                              return arg
                              >
                              Obviously you could use either True or False for the default value. In
                              the case above the function flattens by default. You could also, if you
                              wished, have f() take the flattening argument, and always pass it to g().
                              >
                              Nothing very sophisticated here, just something to help you flex your
                              growing Python and programming muscles.
                              Thanks for your good purposes.

                              TV
                              regards
                              Steve

                              Comment

                              Working...