var or inout parm?

Discussion in 'Python' started by mh@pixar.com, Dec 7, 2008.

  1. Guest

    How can I make a "var" parm, where the called function can modify
    the value of the parameter in the caller?

    def f(x):
    x = x + 1

    n = 1
    f(n)
    # n should now be 2

    Many TIA!!
    Mark


    --
    Mark Harrison
    Pixar Animation Studios
     
    , Dec 7, 2008
    #1
    1. Advertising

  2. Chris Rebert Guest

    On Sun, Dec 7, 2008 at 12:54 AM, <> wrote:
    > How can I make a "var" parm, where the called function can modify
    > the value of the parameter in the caller?


    Not directly possible or encouraged. You can emulate it by sticking
    the value in a container object (e.g. list) though:

    def f(x):
    x[0] += 1 #non-augmented assignment would work too

    n = [1]
    f(n)
    print n[0] #==> 2

    Cheers,
    Chris

    --
    Follow the path of the Iguana...
    http://rebertia.com

    >
    > def f(x):
    > x = x + 1
    >
    > n = 1
    > f(n)
    > # n should now be 2
    >
    > Many TIA!!
    > Mark
    >
    >
    > --
    > Mark Harrison
    > Pixar Animation Studios
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >
     
    Chris Rebert, Dec 7, 2008
    #2
    1. Advertising

  3. schrieb:
    > How can I make a "var" parm, where the called function can modify
    > the value of the parameter in the caller?
    >
    > def f(x):
    > x = x + 1
    >
    > n = 1
    > f(n)
    > # n should now be 2


    Chris showed one way, another is simply returning it. As python can
    return ad-hoc created tuples & unpack them, some C++-wrappers for
    example treat out/inout vars like this:


    def foo(in, inout):
    return inout, out1, out2


    x, y, z = foo(a, x)

    Obviously you are responsible for properly assigning the returned inout
    to the right name again.

    Diez
     
    Diez B. Roggisch, Dec 7, 2008
    #3
  4. On Sun, 07 Dec 2008 08:54:46 +0000, mh wrote:

    > How can I make a "var" parm, where the called function can modify the
    > value of the parameter in the caller?


    By using another language.

    > def f(x):
    > x = x + 1
    >
    > n = 1
    > f(n)
    > # n should now be 2


    Python doesn't work like that. You should read this:

    http://effbot.org/zone/python-objects.htm


    Some work arounds, in order from worst-to-best:


    (1) Use a hard-coded global name:


    x = 1

    def f():
    global x
    x = x + 1

    f()
    assert x == 2


    (2) Wrap the value you want to change in a list, then modify the list in
    place.

    n = [1]

    def f(alist):
    alist[0] = alist[0] + 1

    f(n)
    assert n[0] == 2


    (4) Just use an ordinary function. Functions can return multiple values.

    n = 1

    def f(x):
    return (x+1, 99)

    n, y = f(n)
    assert y == 99
    assert n == 2


    (5) Find another way to solve your problem.

    Why do you think you need var parameters? What problem are you hoping to
    solve by using them? As a former Pascal programmer, I missed var
    parameters at first, but now I don't.




    --
    Steven
     
    Steven D'Aprano, Dec 7, 2008
    #4
  5. wrote:
    > How can I make a "var" parm, where the called function can modify
    > the value of the parameter in the caller?
    >
    > def f(x):
    > x = x + 1
    >
    > n = 1
    > f(n)
    > # n should now be 2
    >
    > Many TIA!!
    > Mark
    >
    >


    Why not run it and see?

    Your function returns None.

    The function in effect takes a copy of
    n. n is not changed.

    Colin W.
     
    Colin J. Williams, Dec 7, 2008
    #5
  6. Colin J. Williams a écrit :
    > wrote:
    >> How can I make a "var" parm, where the called function can modify
    >> the value of the parameter in the caller?
    >>
    >> def f(x):
    >> x = x + 1
    >>
    >> n = 1
    >> f(n)
    >> # n should now be 2
    >>
    >> Many TIA!!
    >> Mark
    >>
    >>

    >
    > Why not run it and see?
    >
    > Your function returns None.
    >
    > The function in effect takes a copy of n.


    Nope, it takes the object bound to global name 'n'.
     
    Bruno Desthuilliers, Dec 8, 2008
    #6
  7. Chris Rebert Guest

    On Mon, Dec 8, 2008 at 12:26 AM, Bruno Desthuilliers
    <> wrote:
    > Colin J. Williams a écrit :
    >>
    >> wrote:
    >>>
    >>> How can I make a "var" parm, where the called function can modify
    >>> the value of the parameter in the caller?
    >>>
    >>> def f(x):
    >>> x = x + 1
    >>>
    >>> n = 1
    >>> f(n)
    >>> # n should now be 2
    >>>
    >>> Many TIA!!
    >>> Mark
    >>>
    >>>

    >>
    >> Why not run it and see?
    >>
    >> Your function returns None.
    >>
    >> The function in effect takes a copy of n.

    >
    > Nope, it takes the object bound to global name 'n'.


    See Also: the earlier heated debate thread over what evaluation
    strategy Python uses (Survey says!: call-by-object).

    Cheers,
    Chris

    --
    Follow the path of the Iguana...
    http://rebertia.com

    >
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >
     
    Chris Rebert, Dec 8, 2008
    #7
  8. Aaron Brady Guest

    On Dec 7, 2:54 am, wrote:
    > How can I make a "var" parm, where the called function can modify
    > the value of the parameter in the caller?
    >
    > def f(x):
    >     x = x + 1
    >
    > n = 1
    > f(n)
    > # n should now be 2


    You can't. 'n' would need a 'set_to' method, which it doesn't have.
    Otherwise, that's not what the equal sign does.
     
    Aaron Brady, Dec 8, 2008
    #8
  9. Guest

    Chris Rebert <> wrote:
    > Not directly possible or encouraged. You can emulate it by sticking
    > the value in a container object (e.g. list) though:


    Thanks, that's just what I needed. I'm using this to monkeypatch
    a test driver into some code that I can't touch, otherwise
    I would just have the function return a tuple with the replacement
    values.

    Cheers!
    Mark

    --
    Mark Harrison
    Pixar Animation Studios
     
    , Dec 10, 2008
    #9
  10. On Mon, 2008-12-08 at 00:57 -0800, Chris Rebert wrote:
    > On Mon, Dec 8, 2008 at 12:26 AM, Bruno Desthuilliers
    > <> wrote:
    > > Colin J. Williams a écrit :
    > >>
    > >> wrote:
    > >>>
    > >>> How can I make a "var" parm, where the called function can modify
    > >>> the value of the parameter in the caller?
    > >>>
    > >>> def f(x):
    > >>> x = x + 1
    > >>>
    > >>> n = 1
    > >>> f(n)
    > >>> # n should now be 2
    > >>>
    > >>> Many TIA!!
    > >>> Mark
    > >>>
    > >>>
    > >>
    > >> Why not run it and see?
    > >>
    > >> Your function returns None.
    > >>
    > >> The function in effect takes a copy of n.

    > >
    > > Nope, it takes the object bound to global name 'n'.

    >
    > See Also: the earlier heated debate thread over what evaluation
    > strategy Python uses (Survey says!: call-by-object).
    >


    Oh dear God. PLEASE don't see also that thread. That way lies madness.
    Just google for call-by-object, and ignore the hell out of that thread.



    > Cheers,
    > Chris
    >
     
    J. Clifford Dyer, Dec 10, 2008
    #10
  11. Joe Strout Guest

    On Dec 10, 2008, at 4:29 PM, J. Clifford Dyer wrote:

    >>>> wrote:
    >>>>>
    >>>>> How can I make a "var" parm, where the called function can modify
    >>>>> the value of the parameter in the caller?
    >>>>>

    >> See Also: the earlier heated debate thread over what evaluation
    >> strategy Python uses (Survey says!: call-by-object).
    >>

    >
    > Oh dear God. PLEASE don't see also that thread. That way lies
    > madness.
    > Just google for call-by-object, and ignore the hell out of that
    > thread.


    Agreed on that point!

    Anyway, to the OP, see <http://www.strout.net/info/coding/valref/> for
    a detailed explanation of why you can't do quite what you're asking
    for in Python (or Java, for that matter).

    Best,
    - Joe
     
    Joe Strout, Dec 10, 2008
    #11
  12. Joe Strout a écrit :
    > On Dec 10, 2008, at 4:29 PM, J. Clifford Dyer wrote:
    >
    >>>>> wrote:
    >>>>>>
    >>>>>> How can I make a "var" parm, where the called function can modify
    >>>>>> the value of the parameter in the caller?
    >>>>>>
    >>> See Also: the earlier heated debate thread over what evaluation
    >>> strategy Python uses (Survey says!: call-by-object).
    >>>

    >>
    >> Oh dear God. PLEASE don't see also that thread. That way lies madness.
    >> Just google for call-by-object, and ignore the hell out of that thread.

    >
    > Agreed on that point!
    >
    > Anyway, to the OP, see <http://www.strout.net/info/coding/valref/>


    Do you really want to start a new flame war, Joe ?-)
     
    Bruno Desthuilliers, Dec 11, 2008
    #12
  13. Guest

    J. Clifford Dyer <> wrote:
    > Just google for call-by-object, and ignore the hell out of that thread.


    Now I've got to go read it! ;-)

    --
    Mark Harrison
    Pixar Animation Studios
     
    , Dec 11, 2008
    #13
  14. sturlamolden Guest

    On Dec 7, 9:54 am, wrote:

    > How can I make a "var" parm, where the called function can modify
    > the value of the parameter in the caller?
    >
    > def f(x):
    > x = x + 1


    Short ansver:

    You can modify function parameters if they are mutable. If they are
    immutable any attempt to modify the parameter will trigger a copy.

    You cannot modify parameters by rebinding. x = x + 1 is a rebinding. x
    += 1 is not.

    If you need to modify immutable parameters or do the modification by
    rebinding, pass the variable back. Python allows multiple return
    values.
     
    sturlamolden, Dec 12, 2008
    #14
  15. Chris Rebert Guest

    On Fri, Dec 12, 2008 at 4:34 AM, sturlamolden <> wrote:
    <snip>
    > You cannot modify parameters by rebinding. x = x + 1 is a rebinding. x
    > += 1 is not.


    Python begs to differ, as those two statements are both semantically
    identical in this case:

    Python 2.6 (r26:66714, Nov 18 2008, 21:48:52)
    [GCC 4.0.1 (Apple Inc. build 5484)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> x = 2
    >>> id (x)

    8405372
    >>> x += 1
    >>> id(x)

    8405360
    >>> x = x + 1
    >>> id(x)

    8405348

    If you were talking about lists rather than integers though, you'd be
    absolutely correct, as the += ends up being a method call to __iadd__
    instead of a plain assignment.

    Cheers,
    Chris

    --
    Follow the path of the Iguana...
    http://rebertia.com
     
    Chris Rebert, Dec 12, 2008
    #15
  16. sturlamolden Guest

    On Dec 12, 1:44 pm, "Chris Rebert" <> wrote:

    > Python begs to differ, as those two statements are both semantically
    > identical in this case:


    That is because integers are immutable. When x += 1 is done on an int,
    there will be a rebinding. But try the same on say, a numpy array, and
    the result will be different:

    >>> import numpy
    >>> x = numpy.zeros(10)
    >>> id(x)

    19504848
    >>> x += 1
    >>> id(x)

    19504848
    >>> x = x + 1
    >>> id(x)

    10451488


    Whereas:

    >>> x = 1
    >>> id(x)

    10051256
    >>> x += 1
    >>> id(x)

    10051244
    >>> x = x + 1
    >>> id(x)

    10051232
     
    sturlamolden, Dec 12, 2008
    #16
  17. sturlamolden Guest

    On Dec 12, 1:56 pm, sturlamolden <> wrote:

    > That is because integers are immutable. When x += 1 is done on an int,
    > there will be a rebinding. But try the same on say, a numpy array, and
    > the result will be different:



    And a consequence of this is, if you have a function like

    def foobar(x):
    x += 1

    then the parameter x will be modified given that x have mutable type.

    However, if we have a function like

    def foobar(x):
    x = x + 1

    then x will not be modified, mutable or not.

    (Well, you could abuse operator overlaoding to make unexpected side
    effects in the latter case. But except for such insanity it will not
    have side-effects.)
     
    sturlamolden, Dec 12, 2008
    #17
  18. Steve Holden Guest

    sturlamolden wrote:
    > On Dec 12, 1:56 pm, sturlamolden <> wrote:
    >
    >> That is because integers are immutable. When x += 1 is done on an int,
    >> there will be a rebinding. But try the same on say, a numpy array, and
    >> the result will be different:

    >
    >
    > And a consequence of this is, if you have a function like
    >
    > def foobar(x):
    > x += 1
    >
    > then the parameter x will be modified given that x have mutable type.
    >
    > However, if we have a function like
    >
    > def foobar(x):
    > x = x + 1
    >
    > then x will not be modified, mutable or not.
    >
    > (Well, you could abuse operator overlaoding to make unexpected side
    > effects in the latter case. But except for such insanity it will not
    > have side-effects.)
    >

    This was all thrashed out exhaustively in the still-feared call
    semantics thread. Yes, augmented operations work differently on mutable
    and immutable objects. Nothing to see here, move right along ...

    regards
    Steve
    --
    Steve Holden +1 571 484 6266 +1 800 494 3119
    Holden Web LLC http://www.holdenweb.com/
     
    Steve Holden, Dec 12, 2008
    #18
  19. sturlamolden <> writes:

    > On Dec 12, 1:44 pm, "Chris Rebert" <> wrote:
    >
    >> Python begs to differ, as those two statements are both semantically
    >> identical in this case:

    >
    > That is because integers are immutable. When x += 1 is done on an int,
    > there will be a rebinding. But try the same on say, a numpy array, and
    > the result will be different:


    The result will be different, but a still occurs! You usually don't
    notice it because augmented assignments with side effect are normally
    careful to return the same object, so rebinding is a no-op. But in
    some cases, that can byte you. For example, tupleobj[0] += 1 raises
    an exception even when tupleobj[0] is mutable. Taking the numpy
    example:

    >>> import numpy
    >>> t = (numpy.zeros(10),)
    >>> t

    (array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]),)
    >>> t[0] += 1

    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: 'tuple' object does not support item assignment

    Of course, the side effect occurs before the exception, so:

    >>> t[0]

    array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
     
    Hrvoje Niksic, Dec 12, 2008
    #19
  20. sturlamolden Guest

    On Dec 12, 2:34 pm, Hrvoje Niksic <> wrote:

    > >>> import numpy
    > >>> t = (numpy.zeros(10),)
    > >>> t

    >
    > (array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]),)>>> t[0] += 1
    >
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in <module>
    > TypeError: 'tuple' object does not support item assignment
    >
    > Of course, the side effect occurs before the exception, so:
    >
    > >>> t[0]


    > array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])



    Actually I would consider this to be a bug. The tuple is immutable,
    but no mutation of the tuple is ever attempted.

    Sturla Molden
     
    sturlamolden, Dec 12, 2008
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. cubes
    Replies:
    2
    Views:
    20,078
    cubes
    Dec 9, 2005
  2. Gene Wirchenko
    Replies:
    22
    Views:
    766
    Jeffrey Schwab
    Dec 19, 2003
  3. =?ISO-8859-15?Q?Fr=E9d=E9ric_Lochon?=

    connecting std_logic inout ports and std_logic_vector inout port

    =?ISO-8859-15?Q?Fr=E9d=E9ric_Lochon?=, Nov 6, 2007, in forum: VHDL
    Replies:
    3
    Views:
    900
  4. Ken

    inout to inout

    Ken, May 9, 2008, in forum: VHDL
    Replies:
    2
    Views:
    662
    Aiken
    May 9, 2008
  5. THurkmans
    Replies:
    14
    Views:
    1,955
    Mike Treseler
    Aug 11, 2009
Loading...

Share This Page