Mutability of function arguments?

Discussion in 'Python' started by ex_ottoyuhr, Dec 8, 2005.

  1. ex_ottoyuhr

    ex_ottoyuhr Guest

    I'm trying to create a function that can take arguments, say, foo and
    bar, and modify the original copies of foo and bar as well as its local
    versions -- the equivalent of C++ funct(&foo, &bar).

    I've looked around on this newsgroup and elsewhere, and I gather that
    this is a very common concern in Python, but one which is ordinarily
    answered with "No, you can't. Neat, huh?" A few websites, newsgroup
    posts, etc. have recommended that one ask for a more "Pythonic" way of
    doing things; so, is there one, or at least one that doesn't involve
    using objects as wrappers for mutable arguments?

    And, indeed, would that approach work? Would declaring:

    class FooWrapper :
    __init__(fooToLoad) :
    self.foo = fooToLoad

    mean that I could now declare a FooWrapper holding a foo, pass the
    FooWrapper to a function, and have the function conclude with the foo
    within the FooWrapper now modified?

    Thanks in advance for everyone's time; I hope I'm comprehensible.
     
    ex_ottoyuhr, Dec 8, 2005
    #1
    1. Advertising


  2. >
    > And, indeed, would that approach work? Would declaring:
    >
    > class FooWrapper :
    > __init__(fooToLoad) :
    > self.foo = fooToLoad
    >
    > mean that I could now declare a FooWrapper holding a foo, pass the
    > FooWrapper to a function, and have the function conclude with the foo
    > within the FooWrapper now modified?
    >

    Yes, passing FooWrapper will pass by reference to a python function
    thereby allowing you to edit the fooToLoad

    HTH,

    carl


    --

    Carl J. Van Arsdall

    Build and Release
    MontaVista Software
     
    Carl J. Van Arsdall, Dec 8, 2005
    #2
    1. Advertising

  3. "ex_ottoyuhr" wrote:

    > I've looked around on this newsgroup and elsewhere, and I gather that
    > this is a very common concern in Python, but one which is ordinarily
    > answered with "No, you can't. Neat, huh?" A few websites, newsgroup
    > posts, etc. have recommended that one ask for a more "Pythonic" way of
    > doing things; so, is there one, or at least one that doesn't involve
    > using objects as wrappers for mutable arguments?


    anyone that holds a reference to a mutable object can modify it, and
    everyone that has the same reference will see the changes. assignment
    copies references, not values:

    >>> foo = []
    >>> value = foo
    >>> foo.append("hello")
    >>> foo.append("world")
    >>> value

    ['hello', 'world']

    > And, indeed, would that approach work? Would declaring:
    >
    > class FooWrapper :
    > __init__(fooToLoad) :
    > self.foo = fooToLoad
    >
    > mean that I could now declare a FooWrapper holding a foo, pass the
    > FooWrapper to a function, and have the function conclude with the foo
    > within the FooWrapper now modified?


    if self.foo is a mutable object, and your function is modifying it in
    place, yes:

    >>> class FooWrapper:

    ... def __init__(self, fooToLoad):
    ... self.foo = fooToLoad
    ...
    >>> value = []
    >>> foo = FooWrapper(value)
    >>>
    >>> foo.foo

    []
    >>> value

    []
    >>> def mutator(x):

    ... x.foo.append("hello")
    ...
    >>> mutator(foo)
    >>> mutator(foo)
    >>>
    >>> foo.foo

    ['hello', 'hello']
    >>> value

    ['hello', 'hello']

    however, if the mutator replaces the wrapped object, the original object
    will not see the changes. you can still see them via the wrapper, of course:

    >>> def mutator(x):

    ... x.foo = ["goodbye"]
    ...
    >>> mutator(foo)
    >>> foo.foo

    ['goodbye']
    >>> value

    ['hello', 'hello']

    this might help:

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

    </F>
     
    Fredrik Lundh, Dec 8, 2005
    #3
  4. ex_ottoyuhr

    ex_ottoyuhr Guest

    (Re. mutability question:)

    Update, never mind. I found that the FooWrapper solution isn't so bad
    after all -- and even better is putting the variable in question in a
    different module entirely.

    However, anyone who wants to answer the question is still welcome to.
    Sorry to be a bother, and to have posted before I thought... :)
     
    ex_ottoyuhr, Dec 8, 2005
    #4
  5. ex_ottoyuhr wrote:
    > I'm trying to create a function that can take arguments, say, foo and
    > bar, and modify the original copies of foo and bar as well as its local
    > versions -- the equivalent of C++ funct(&foo, &bar).
    >
    > I've looked around on this newsgroup and elsewhere, and I gather that
    > this is a very common concern in Python, but one which is ordinarily
    > answered with "No, you can't. Neat, huh?" A few websites, newsgroup
    > posts, etc. have recommended that one ask for a more "Pythonic" way of
    > doing things; so, is there one, or at least one that doesn't involve
    > using objects as wrappers for mutable arguments?
    >
    > And, indeed, would that approach work? Would declaring:
    >
    > class FooWrapper :
    > __init__(fooToLoad) :
    > self.foo = fooToLoad
    >
    > mean that I could now declare a FooWrapper holding a foo, pass the
    > FooWrapper to a function, and have the function conclude with the foo
    > within the FooWrapper now modified?


    Well, you can test it yourself:

    >>> class wrapper(object):

    .... def __init__(self, val):
    .... self.val = val
    ....
    >>> w = wrapper(42)
    >>> w.val

    42
    >>> def foo(w):

    .... w.val = 11
    ....
    >>> foo(w)
    >>> w.val

    11
    >>>


    >
    > Thanks in advance for everyone's time; I hope I'm comprehensible.


    You're comprehensible, but I think that you're also thinking in C++.
    The object model that Python follows is very different -- instead of
    thinking of assignment meaning
    "Stick this value into this named location", you need to switch to
    thinking of assignment as meaning "stick this name onto that object
    until I tell you otherwise".

    If you're trying to return multiple values from a function, Python lets
    you do that

    >>> def multiFoo(x, y, z):

    .... return x*2, y*2, z*2
    ....
    >>> x = 1
    >>> y = 2
    >>> z = 3
    >>> x, y, z = multiFoo(x, y, z)
    >>> x

    2
    >>> y

    4
    >>> z

    6
    >>>

    --
    // Today's Oblique Strategy (© Brian Eno/Peter Schmidt):
    // Repetition is a form of change
    // Brett g Porter *
     
    Brett g Porter, Dec 8, 2005
    #5
  6. ex_ottoyuhr

    Mark Tolonen Guest

    "ex_ottoyuhr" <> wrote in message
    news:...
    > I'm trying to create a function that can take arguments, say, foo and
    > bar, and modify the original copies of foo and bar as well as its local
    > versions -- the equivalent of C++ funct(&foo, &bar).
    >
    > I've looked around on this newsgroup and elsewhere, and I gather that
    > this is a very common concern in Python, but one which is ordinarily
    > answered with "No, you can't. Neat, huh?" A few websites, newsgroup
    > posts, etc. have recommended that one ask for a more "Pythonic" way of
    > doing things; so, is there one, or at least one that doesn't involve
    > using objects as wrappers for mutable arguments?
    >
    > And, indeed, would that approach work? Would declaring:
    >
    > class FooWrapper :
    > __init__(fooToLoad) :
    > self.foo = fooToLoad
    >
    > mean that I could now declare a FooWrapper holding a foo, pass the
    > FooWrapper to a function, and have the function conclude with the foo
    > within the FooWrapper now modified?
    >
    > Thanks in advance for everyone's time; I hope I'm comprehensible.
    >


    Python isn't C++ and there is no need to return multiple values by modifying
    function parameters:

    >>> def funct(a,b):

    .... return a+1,b+1
    ....
    >>> foo,bar=1,2
    >>> print foo,bar

    2 3
    >>> foo,bar=funct(foo,bar)
    >>> print foo,bar

    3 4
    >>>


    -Mark
     
    Mark Tolonen, Dec 8, 2005
    #6
  7. ex_ottoyuhr

    Mike Meyer Guest

    "ex_ottoyuhr" <> writes:
    > I'm trying to create a function that can take arguments, say, foo and
    > bar, and modify the original copies of foo and bar as well as its local
    > versions -- the equivalent of C++ funct(&foo, &bar).


    C++'s '&' causes an argument to be passed by reference. Python does
    that with all arguments. Any changes you make to the argument in the
    function will be seen in the caller unless you explicitly make a copy
    to pass.

    > I've looked around on this newsgroup and elsewhere, and I gather that
    > this is a very common concern in Python, but one which is ordinarily
    > answered with "No, you can't. Neat, huh?" A few websites, newsgroup
    > posts, etc. have recommended that one ask for a more "Pythonic" way of
    > doing things; so, is there one, or at least one that doesn't involve
    > using objects as wrappers for mutable arguments?


    If your arguments are mutable, you don't need to do anything to be
    able to change them - just call the mutator methods. If your arguments
    aren't mutable, then you can't change them, either in the function or
    in the original namespace.

    If what you really want to do is rebind a variable in the calling
    namespace - well, you can't do that. The standard way to deal with the
    usual uses for passing references in C is to return the value (or
    values - Python handles multi-valued return and assignment much
    cleaner than C++) and rebind the variables at the point of the call.

    If you insist on writing C/C++ in Python, you can wrap an immutable
    object in an instance of class with a method to let you change it, as
    you suggest:

    > And, indeed, would that approach work? Would declaring:
    > class FooWrapper :
    > __init__(fooToLoad) :
    > self.foo = fooToLoad


    > mean that I could now declare a FooWrapper holding a foo, pass the
    > FooWrapper to a function, and have the function conclude with the foo
    > within the FooWrapper now modified?


    If you like an extended lambda calculus syntax, you can use my Ref
    class: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/456150.

    <mike
    --
    Mike Meyer <> http://www.mired.org/home/mwm/
    Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
     
    Mike Meyer, Dec 8, 2005
    #7
  8. ex_ottoyuhr

    Guest

    Mike Meyer wrote:
    > "ex_ottoyuhr" <> writes:
    > > I'm trying to create a function that can take arguments, say, foo and
    > > bar, and modify the original copies of foo and bar as well as its local
    > > versions -- the equivalent of C++ funct(&foo, &bar).

    >
    > C++'s '&' causes an argument to be passed by reference. Python does
    > that with all arguments. Any changes you make to the argument in the
    > function will be seen in the caller unless you explicitly make a copy
    > to pass.
    >

    except when foo and bar are bound to immutable objects.

    In C:

    int foo=1;
    int bar=2;

    void update(int *a, int *b) { *a=3; *b=4}

    update(&foo, &bar);

    In Python:

    foo=1
    bar=2

    def update(a,b): a=3; b=4

    update(foo,bar)

    Many people from C/C++ background would be tricked for this situation.
     
    , Dec 8, 2005
    #8
  9. ex_ottoyuhr

    Mike Meyer Guest

    writes:
    > Mike Meyer wrote:
    >> "ex_ottoyuhr" <> writes:
    >> > I'm trying to create a function that can take arguments, say, foo and
    >> > bar, and modify the original copies of foo and bar as well as its local
    >> > versions -- the equivalent of C++ funct(&foo, &bar).

    >>
    >> C++'s '&' causes an argument to be passed by reference. Python does
    >> that with all arguments. Any changes you make to the argument in the
    >> function will be seen in the caller unless you explicitly make a copy
    >> to pass.
    >>

    > except when foo and bar are bound to immutable objects.


    Wrong.

    > In C:
    >
    > int foo=1;
    > int bar=2;
    >
    > void update(int *a, int *b) { *a=3; *b=4}
    >
    > update(&foo, &bar);


    Note that this update is using an assignment statement, and thus
    changing the arguments.

    > In Python:
    >
    > foo=1
    > bar=2
    >
    > def update(a,b): a=3; b=4
    >
    > update(foo,bar)


    This update isn't changing the objects, it's rebinding the names in
    the local name space. Since you didn't change the objects, there's no
    change to see in the calling environment.

    > Many people from C/C++ background would be tricked for this situation.


    That's because they don't understand binding. Any language that has
    bindings instead of has assignments will "trick" them this way.

    <mike
    --
    Mike Meyer <> http://www.mired.org/home/mwm/
    Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
     
    Mike Meyer, Dec 8, 2005
    #9
  10. Mike Meyer <> wrote:

    > > Many people from C/C++ background would be tricked for this situation.

    >
    > That's because they don't understand binding. Any language that has
    > bindings instead of has assignments will "trick" them this way.


    ....Java being probably the most popular example...


    Alex
     
    Alex Martelli, Dec 8, 2005
    #10
  11. ex_ottoyuhr

    Guest

    Mike Meyer wrote:
    > writes:
    > > Mike Meyer wrote:
    > >> "ex_ottoyuhr" <> writes:
    > >> > I'm trying to create a function that can take arguments, say, foo and
    > >> > bar, and modify the original copies of foo and bar as well as its local
    > >> > versions -- the equivalent of C++ funct(&foo, &bar).
    > >>
    > >> C++'s '&' causes an argument to be passed by reference. Python does
    > >> that with all arguments. Any changes you make to the argument in the
    > >> function will be seen in the caller unless you explicitly make a copy
    > >> to pass.
    > >>

    > > except when foo and bar are bound to immutable objects.

    >
    > Wrong.
    >
    > > In C:
    > >
    > > int foo=1;
    > > int bar=2;
    > >
    > > void update(int *a, int *b) { *a=3; *b=4}
    > >
    > > update(&foo, &bar);

    >
    > Note that this update is using an assignment statement, and thus
    > changing the arguments.


    void update(int a, int b) { a=3; b=4}

    Is this also an assignment statement ?

    >
    > > In Python:
    > >
    > > foo=1
    > > bar=2
    > >
    > > def update(a,b): a=3; b=4
    > >
    > > update(foo,bar)

    >
    > This update isn't changing the objects, it's rebinding the names in
    > the local name space. Since you didn't change the objects, there's no
    > change to see in the calling environment.
    >
    > > Many people from C/C++ background would be tricked for this situation.

    >
    > That's because they don't understand binding. Any language that has
    > bindings instead of has assignments will "trick" them this way.
    >

    Sure, any language that behave like this would trick them, I am not
    saying python is the only one or that there is anything wrong with this
    behaviour. I was just saying that it is a situation that they get
    tricked, because of their "perception" about "=", especially when they
    are told that any change to the arguments are seen by the caller.
     
    , Dec 8, 2005
    #11
  12. ex_ottoyuhr

    Mike Meyer Guest

    writes:
    > Mike Meyer wrote:
    >> writes:
    >> > Mike Meyer wrote:
    >> >> "ex_ottoyuhr" <> writes:
    >> >> > I'm trying to create a function that can take arguments, say, foo and
    >> >> > bar, and modify the original copies of foo and bar as well as its local
    >> >> > versions -- the equivalent of C++ funct(&foo, &bar).
    >> >> C++'s '&' causes an argument to be passed by reference. Python does
    >> >> that with all arguments. Any changes you make to the argument in the
    >> >> function will be seen in the caller unless you explicitly make a copy
    >> >> to pass.
    >> > except when foo and bar are bound to immutable objects.

    >> Wrong.
    >> > In C:
    >> >
    >> > int foo=1;
    >> > int bar=2;
    >> >
    >> > void update(int *a, int *b) { *a=3; *b=4}
    >> >
    >> > update(&foo, &bar);

    >>
    >> Note that this update is using an assignment statement, and thus
    >> changing the arguments.

    > void update(int a, int b) { a=3; b=4}
    > Is this also an assignment statement ?


    Yes. But C calls by value, and passes copies of the original a and b
    in. So in this case, you change the copies.

    >> > In Python:
    >> >
    >> > foo=1
    >> > bar=2
    >> >
    >> > def update(a,b): a=3; b=4
    >> >
    >> > update(foo,bar)

    >> This update isn't changing the objects, it's rebinding the names in
    >> the local name space. Since you didn't change the objects, there's no
    >> change to see in the calling environment.
    >> > Many people from C/C++ background would be tricked for this situation.

    >> That's because they don't understand binding. Any language that has
    >> bindings instead of has assignments will "trick" them this way.

    > Sure, any language that behave like this would trick them, I am not
    > saying python is the only one or that there is anything wrong with this
    > behaviour. I was just saying that it is a situation that they get
    > tricked, because of their "perception" about "=", especially when they
    > are told that any change to the arguments are seen by the caller.


    Except "trick" is a poor word choice. Nobody is playing a trick on
    them - they just don't understand what is going on.

    <mike
    --
    Mike Meyer <> http://www.mired.org/home/mwm/
    Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
     
    Mike Meyer, Dec 8, 2005
    #12
  13. ex_ottoyuhr

    Guest

    Mike Meyer wrote:
    > Except "trick" is a poor word choice. Nobody is playing a trick on
    > them - they just don't understand what is going on.
    >

    oops, never thought about the negative meaning of it, it is just meant
    as "not behave as expected", what would be the word you use then ?
     
    , Dec 8, 2005
    #13
  14. ex_ottoyuhr

    Mike Meyer Guest

    writes:

    >> Except "trick" is a poor word choice. Nobody is playing a trick on
    >> them - they just don't understand what is going on.

    > oops, never thought about the negative meaning of it, it is just meant
    > as "not behave as expected", what would be the word you use then ?


    Surprise?

    <mike
    --
    Mike Meyer <> http://www.mired.org/home/mwm/
    Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
     
    Mike Meyer, Dec 8, 2005
    #14
  15. ex_ottoyuhr wrote:
    > I'm trying to create a function that can take arguments, say, foo and
    > bar, and modify the original copies of foo and bar as well as its local
    > versions -- the equivalent of C++ funct(&foo, &bar).


    This is already what you have. In Python, all you have are references to
    objects, there is no "local version".

    > I've looked around on this newsgroup and elsewhere, and I gather that
    > this is a very common concern in Python, but one which is ordinarily
    > answered with "No, you can't. Neat, huh?"


    Pardon ???

    >>> def appendToList(aList, aValue):

    .... aList.append(aValue)
    ....
    >>> mylist = range(10)
    >>> mylist

    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> appendToList(mylist, 42)
    >>> mylist

    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 42]
    >>>


    Now the usual considerations apply :
    - rebinding an arg has of course only local effect
    - immutable objects are still immutables

    Also note that since
    1/ Python as a good support for exception handling
    2/ a function can return multiple values [1],
    there is less need for such constructs than in C or C++.

    [1] the truth is that the function can return a unique tuple, that can
    be unpacked as any other.

    --
    bruno desthuilliers
    python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
    p in ''.split('@')])"
     
    bruno at modulix, Dec 8, 2005
    #15
  16. ex_ottoyuhr

    Kent Johnson Guest

    Mike Meyer wrote:
    > "ex_ottoyuhr" <> writes:
    >
    >>I'm trying to create a function that can take arguments, say, foo and
    >>bar, and modify the original copies of foo and bar as well as its local
    >>versions -- the equivalent of C++ funct(&foo, &bar).

    >
    >
    > C++'s '&' causes an argument to be passed by reference. Python does
    > that with all arguments. Any changes you make to the argument in the
    > function will be seen in the caller unless you explicitly make a copy
    > to pass.


    I would say, from the point of view of a C++ programmer, Python passes
    references by value. In other words if you think of variables as
    pointers (references) to values, and function call as passing the
    reference by value, the behaviour of Python makes sense.

    Kent
     
    Kent Johnson, Dec 8, 2005
    #16
  17. ex_ottoyuhr

    Mike Meyer Guest

    Kent Johnson <> writes:
    > Mike Meyer wrote:
    >> "ex_ottoyuhr" <> writes:
    >>
    >>>I'm trying to create a function that can take arguments, say, foo and
    >>>bar, and modify the original copies of foo and bar as well as its local
    >>>versions -- the equivalent of C++ funct(&foo, &bar).

    >> C++'s '&' causes an argument to be passed by reference. Python does
    >> that with all arguments. Any changes you make to the argument in the
    >> function will be seen in the caller unless you explicitly make a copy
    >> to pass.

    > I would say, from the point of view of a C++ programmer, Python passes
    > references by value. In other words if you think of variables as
    > pointers (references) to values, and function call as passing the
    > reference by value, the behaviour of Python makes sense.


    While the description is right, the terminology is wrong, and places
    the emphasis in the wrong place.

    Your description of "passes references by value" is a description of
    call by reference. C passes all arguments by value, to pass a
    reference, the C programmer creates the reference to the value "by
    hand", then dereferences it by hand at the other end. So C's
    "call-by-reference" passes the reference by value. There's no
    difference between C's call-by-reference and Python's
    call-by-reference, and using different words to try and imply there is
    will just cause problems further on.

    The real difference is in the way names behave in the two
    languages. As you put it, "variables are references to values", except
    Python names don't have most of the things associated with variables
    in other programming languages, so it's better to call them names. We
    use "bound" to show that we're not copying a value over a fixed memory
    location, hence "names are bound to values." This is the crucial
    point, and the one that need to be emphasized.

    <mike
    --
    Mike Meyer <> http://www.mired.org/home/mwm/
    Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
     
    Mike Meyer, Dec 8, 2005
    #17
  18. Mike Meyer wrote:

    > Your description of "passes references by value" is a description of
    > call by reference. C passes all arguments by value, to pass a
    > reference, the C programmer creates the reference to the value "by
    > hand", then dereferences it by hand at the other end. So C's
    > "call-by-reference" passes the reference by value. There's no
    > difference between C's call-by-reference and Python's
    > call-by-reference, and using different words to try and imply there is
    > will just cause problems further on.


    can you guys please stop using "call by value" and "call by reference"
    when you discuss Python. both terms have established meanings, and
    Python's argument passing model doesn't match any of them.

    this was known some 30 years ago; here's a quote from a CLU reference
    manaual from 1979:

    "We call the argument passing technique _call by sharing_,
    because the argument objects are shared between the
    caller and the called routine. This technique does not
    correspond to most traditional argument passing techniques
    (it is similar to argument passing in LISP). In particular IT
    IS NOT call by value because mutations of arguments per-
    formed by the called routine will be visible to the caller.
    And IT IS NOT call by reference because access is not given
    to the variables of the caller, but merely to certain objects."

    (CLU was one of the first languages to use objects in the Python sense,
    as well as the same argument passing model as today's Python)

    established terms for Python's argument passing model are

    call by object

    or

    call by sharing

    for more on this, see the comp.lang.python archives.

    </F>
     
    Fredrik Lundh, Dec 8, 2005
    #18
    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. Edward C. Jones

    Mutability problem when subclassing tuple

    Edward C. Jones, Feb 19, 2004, in forum: Python
    Replies:
    2
    Views:
    603
    Shalabh Chaturvedi
    Feb 19, 2004
  2. gigs

    list mutability

    gigs, Feb 18, 2008, in forum: Python
    Replies:
    1
    Views:
    240
    John Machin
    Feb 18, 2008
  3. named tuple mutability

    , May 14, 2008, in forum: Python
    Replies:
    10
    Views:
    453
    Bruno Desthuilliers
    May 15, 2008
  4. cnb
    Replies:
    1
    Views:
    216
    Alan G Isaac
    Aug 26, 2008
  5. kj
    Replies:
    4
    Views:
    422
    Arnaud Delobelle
    Oct 7, 2010
Loading...

Share This Page