david <db.pub.m...@gmail.com> added the comment:

On 28 August 2010 09:10, Theo Julienne <rep...@bugs.python.org> wrote:
>
> Theo Julienne <theo.julie...@gmail.com> added the comment:
>
> def list_again(foo):
>        foo.append("bar")
>
> def list_again_again(foo):
>        foo = foo + ["1"]
>
>
> The part that can be confusing is that 'foo' is a *copy* of a *reference* to 
> an object. Because 'foo' is a copy, assigning to it will only alter a local 
> copy, while calling methods on it will always call on the original object 
> (because it's a reference to the same place). When an object is mutable, it 
> just has no methods that modify it, so the only way to change it is by 
> assignment, which will never result in changes to the outside function.

Yes exactly!

>There are no special cases, but it does require understanding 
>pass-by-(copy/reference) and object mutability, and is against most people's 
>intuitions.

No that isn't really my point here really.

> The way that behaves is actually how most *programmers* would expect (because 
> they are used to it), though. Every other language I can think of does it 
> this way. For example, in C, a pointer is still a copy of a reference -- if 
> you assign to the pointer, it wont propagate up to the caller. The same goes 
> in Java.

Um sort of. This is kind of confusing right see the code below.

> Perhaps what makes it harder to understand in Python is that everything is an 
> object and looks the same regardless of mutability, whereas other languages 
> typically have conventions (such as capitalising: int, str, Dict, List) to 
> make it clearer when something is an object (which usually means the same as 
> a python mutable object) as opposed to a built-in type (which usually means 
> the same as a python immutable object).

I actually think the problem is that python coders are not aware of
this largely (from my experience) and that the *operators* are going
to behave differently (java, for example,  differs in this respect (
you don't '+' maps )).

Here are some examples of use in other languages. Mapping python can
be found some of them.

foo.cpp
#include <iostream>
#include <string>
using namespace std;

void do_More_Foo(int *it);

int main()
{
        int *foo;
        int bar = 0;
        foo = &bar;
        cout << *foo << " "  << foo << endl;
        do_More_Foo(foo);
        cout << *foo << " "  << foo << endl;
        return 0;
}

void do_More_Foo(int *it)
{
        cout << "do more foo " << it << " " << *it <<endl;
        *it = 9;
}

g++ -Wall -Werror foo.cpp  -lmudflap -fmudflap
./a.out
0 0x7fff0ec19adc
do more foo 0x7fff0ec19adc 0
9 0x7fff0ec19adc

AND in python:
#!/usr/bin/env python

def do_More_Foo(it):
        print "in do_More_Foo"
        print "foo", foo, id(foo), id(foo[0])
        print "it", it, id(it)
        it.pop()
        it.append("9")

if __name__ == "__main__":
        bar = 0
        foo = [bar]
        print id(bar)
        print id(foo[0])
        print foo, id(foo)
        do_More_Foo(foo)
        print "after do_More_Foo", foo, id(foo), id(foo[0])

output:
16307968
16307968
[0] 140400602766512
in do_More_Foo
foo [0] 140400602766512 16307968
it [0] 140400602766512
after do_More_Foo ['9'] 140400602766512 140400602799200

However, this isn't what you expect people to do.
Oh and how did foo get there ;) (surprise! python isn't simple is it ?
- note the id).

So I think most people are going to think about this and write it like this:
#!/usr/bin/env python

def woops(it):
        # erh make foo = 9 ?
        print "foo", foo, id(foo)
        foo = 9
        print "foo", foo, id(foo)

def do_More_Foo(it):
        print "in do_More_Foo"
        print "foo", foo, id(foo)
        print "it", it, id(it)
        it = 9
        print "it", it, id(it)

if __name__ == "__main__":
        foo = 0
        print foo, id(foo)
        do_More_Foo(foo)
        print "after do_More_Foo", foo, id(foo)
        woops(foo)
        print "after do_More_Foo", foo, id(foo)

output:
0 19838720
in do_More_Foo
foo 0 19838720
it 0 19838720
it 9 19838504
after do_More_Foo 0 19838720
foo
Traceback (most recent call last):
  File "python-cpp2.py", line 21, in <module>
    woops(foo)
  File "python-cpp2.py", line 5, in woops
    print "foo", foo, id(foo)
UnboundLocalError: local variable 'foo' referenced before assignment

As you expect it is not the foo you are looking for ;)

foo.java

import java.util.HashMap;

import javax.print.DocFlavor.STRING;

public class foo
{

        public void bar(HashMap<String, String> z)
        {

                z.put("foo", "bar");
                HashMap<String, String> b = z;
                b.put("foo2", "ba2r");
        }

        void magic(String b)
        {
                String c = b;
                b = b.replace('b', 'c');
                System.out.println(c);
                System.out.println(b);
        }

        void moremagic(StringBuilder z)
        {
                z.append("b");
        }
        public static void main(String[] args)
        {
                HashMap<String, String> baz = new HashMap<String, String>();
                foo myfoo = new foo();
                myfoo.bar(baz);
                System.out.println(baz.toString());
                String aaa = "b";
                myfoo.magic(aaa);
                System.out.println(aaa);
                StringBuilder sb = new StringBuilder();
                myfoo.moremagic(sb);
                System.out.println(sb);
        }

}
java foo
{foo2=ba2r, foo=bar}
b
c
b
b

#!/usr/bin/env python

def bar(a_dict):
        a_dict["foo"] = "bar"
        new_dict = a_dict
        a_dict["foo2"] = "ba2r"

def magic(string_b):
        c = string_b
        string_b = string_b.replace('b', 'c')
        print c
        print string_b

def moremagic(list_s):
        list_s.append("b")

if __name__ == "__main__":
        d = dict()
        bar(d)
        print d
        aaa = "b"
        magic(aaa)
        print aaa
        a_list = []
        moremagic(a_list)
        print a_list[0]

python python-java.py
{'foo': 'bar', 'foo2': 'ba2r'}
b
c
b
b

- no problems here :)  - but in python we can use an operator like '+'
on a list which introduces the very confusion I am talking about in
respect to the differing behaviour as I stated at the top of this bug
report. :)

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue9702>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to