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