TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Is Python call-by-value or call-by-reference? Neither.

39 pointsby jknuppover 12 years ago

14 comments

Jachover 12 years ago
Wrong. It's call-by-value, the confusion comes from what, in Python, is considered a value (and when a value is mutable, which is always (with a little ctypes magic), even the built-in number 4). And just like in Java, which also is always call-by-value, Python passes pointers-by-value under the hood which allows for some easy modification.<p>There is an easy test to see if a language supports call-by-reference or not:<p><pre><code> a = 3 b = 4 swap(a,b) print a, b # 4 3 </code></pre> C++ can do this, C can't, C# can't (if you think it can, then so can C), Python can't, Java can't. Therefore, all of those but C++ are call-by-value in all cases.<p>Edit: I hasten to add, the swap() function should be implemented "traditionally". i.e.:<p><pre><code> def swap(x, y): temp = x x = y y = temp</code></pre>
评论 #4783433 未加载
评论 #4783928 未加载
评论 #4784128 未加载
评论 #4783501 未加载
评论 #4783424 未加载
mistercowover 12 years ago
A lot of comments here are talking about how it's "really" just call-by-value. I want to explain why this is unproductive.<p>First, let's acknowledge that the context we're discussing is explaining to someone new to Python how Python works with function arguments.<p>Now, if someone asks if lead-acid batteries work using chemistry, and you say "they use physics", then they will probably end up with a fairly inaccurate picture of how lead-acid batteries work. What you've told them is <i>technically</i> correct, but it isn't practically useful.<p>It is the same if someone asks how Python passes arguments to functions and you say "it's pass-by-value". You've told them something technically correct, but they're going to think inaccurate things like that passing an object to a function copies all of the object's properties like a struct in C.<p>Even if you say "it's pass-by-value but the values are not what you think", you haven't actually <i>added</i> to their understanding by that phrase. You're better off explaining <i>conceptually</i> how it works, describing it as "call-by-sharing", and then explaining what that means. It will signal their brain to allocate space for a new concept, and not to drag in erroneous ideas from existing concepts. After they understand how it works, you can explain that call-by-sharing is actually just a spoonful of sugar to help the call-by-value go down.<p>Here's the thing: words are there to help us communicate. If you use a word in a way that is technically correct but <i>conveys the wrong idea</i> to your listener, you're doing it wrong.<p>Here's the other thing: this is computer science. In computer science, as in all math, you often encounter a concept that is "really just" some other concept. When you come to that realization about a concept that you understand superficially, it can be transformative, taking you to a deeper level of comprehension. When someone asks you about the concept, you'll want to share that deep comprehension with them, so it's natural to want to jump right into it and explain it by connecting it to the general case. But they <i>will not</i> understand if you do that.<p>You can't teach someone addition by starting with ring theory, after all.
评论 #4784068 未加载
评论 #4783959 未加载
lvhover 12 years ago
How is this different from call-by-value, where all values are object references?
评论 #4783602 未加载
manojldsover 12 years ago
Isn't this by definition call by value? The reference / binding is passed by value. Changing the reference to point to something else will not make the other reference to point to the same too.
评论 #4783396 未加载
评论 #4783747 未加载
skittlesover 12 years ago
I'm a C# developer who also programmed in Java in the past. C# and Java both pass pointers by value (which is what Python does too). This is a very important thing to learn when programming C# or Java. A method (or function) in any of these languages can either manipulate the object that the reference points to, or they can reassign the reference to a new object internally (which will leave the original object alone).
adrusiover 12 years ago
this is over complicating the model to avoid saying what for some reason people are terrified to say: that objects are just pointers. when you pass an object you are passing the value of a reference. it's not that scary
评论 #4783446 未加载
评论 #4783888 未加载
alphaBetaGammaover 12 years ago
I have a C based mental model of what is happening. Can anyone comment on whether it is correct?<p>In C terms, I think of all objects (including primitives such as numbers) as a struct with a void* pointer that holds the actual data, and another field that describes how to interpret the data: struct Obj { void* data; ObjDesc descr; }<p>Whenever you do objA=objB you create an new struct Obj with objA.data == objB.data. The same things happens when you pass an object to a function: you create a copy of the Obj.<p>When you modify an Obj, two things can happen: if the Obj is immutable you change where void* data points to: n1 = 4 n2 = b1 n1 = 5 ==&#62; n1.data != n2.data<p>On the other hand, if Obj is mutable, than you don't change void* data, you modify the memory pointed to by data: n1=[] n2=n1 n1.append(1) ==&#62; n1.data == n2.data<p>Is this correct or is mental model going to bite me sometime?
评论 #4784121 未加载
评论 #4783838 未加载
InclinedPlaneover 12 years ago
Python is a truly bizarre language in this regard. It's behavior is unusual and similar only to a few other less well known niche languages such as C# and Java.
评论 #4783994 未加载
评论 #4784033 未加载
评论 #4783817 未加载
评论 #4784130 未加载
pierrebaiover 12 years ago
Python is strictly a call-by-ref language. The author of the blog and many commenter here seem confused. There are two causes:<p>1. Some objects are immutable.<p>This makes some calls seem to be call-by-value, but they are not. A simple look at the generated code makes this obvious. Integers, strings, tuples, ... are passed by reference. It's just that you can't mutate the object being passed.<p>2. The behaviour of the assignment operator is different from most non-functional language.<p>In Python, assignment never mutate values. It assign a new reference to the 'variable' (i.e. the scoped name). This explains clearly why in functions, you can't mutate an immutable object even though it is passed by reference: assignment merely rebind the argument name to a new value.<p>That is why when you want to mutate something in a function in Python, your only recourse is to call a function on that object:<p><pre><code> i = 4 s = 'George' l = [ 'me', 'you'] foo (i, s, l) def foo(a, b, c): a = 3 b = 'Mark' c.append( 42 ) c = [ 2, 1 ] print(i, s, l) # prints 4, 'George', ['me', 'you', 42]</code></pre>
评论 #4784075 未加载
mattdeboardover 12 years ago
Well, regardless of the call-by-x discussion, this is actually a really good explanation of scope and state in Python. Code like:<p><pre><code> def grow(array): array.append(1) array = [] grow(array) </code></pre> leads to such needless complexity.
rmcover 12 years ago
I highly recommend this site: <a href="http://pythontutor.com/" rel="nofollow">http://pythontutor.com/</a> It'll parse and execute python code, including showing what variables are pointing to what obects.
mistercowover 12 years ago
Since you explained name binding anyway, a useful way to describe Python might just be "call-by-binding".
tsuyoshiover 12 years ago
I'm not too familiar with Python, but the semantics of Python described here match every other language that I can think of (including C). Can anyone give me an example of a language that is actually call-by-reference?
评论 #4784019 未加载
评论 #4784989 未加载
brabbinsover 12 years ago
Perhaps this is a digression, but there are some misunderstandings in this blog post about the memory model in his C++ example. Since the author goes to lengths to be precise and exact in terminology and his explanations, it would be good to clarify some things.<p>For the example code C++ given:<p><pre><code> string some_guy = "Fred"; // ... some_guy = "George"; </code></pre> Here is the author's explanation:<p><pre><code> In the above, the variable some_guy refers to a location in memory, and the value 'Fred' is inserted in that location (indeed, we can take the address of some_guy to determine the portion of memory to which it refers). Later, the contents of the memory location referred to by some_guy are changed to 'George'. The previous value no longer exists; it was overwritten. This likely matches your intuitive understanding (even if you don't program in C++). </code></pre> There are several incorrect statements here.<p>A. "the variable some_guy refers to a location in memory, and the value 'Fred' is inserted in that location" Not true. The variable some_guy refers to a location in memory, but that location contains a <i>pointer</i> to a region of memory with the value "Fred". More on this in a bit.<p>B. "indeed, we can take the address of some_guy to determine the portion of memory to which it refers". Again, not true in the way the author probably intended. The address of 'some_guy' will be the address on the stack where the variable is located. The value at that address on the stack will be a pointer to a separate region of memory containing "Fred".<p>C. "Later, the contents of the memory location referred to by some_guy are changed to 'George'." To be precise, the contents of the memory location referred to by some_guy are changed to a new <i>pointer</i> to a different region of memory containing "George".<p>D. "the previous value no longer exists; it was overwritten." The values "Fred" and "George" exist through the entire lifetime of the program. They are string constants, which are compiled in to the data section of the program binary. The author is correct on one point: the value of 'some_guy' is overwritten during the reassignment. However, the value in this case is simply a pointer, not a string.<p>We can verify my claims experimentally. On my system (Ubuntu 11.04 32-bit, g++ 4.5.2), I wrote the following test program:<p><pre><code> //a.cpp #include &#60;string&#62; using namespace std; int main() { string some_guy = "Fred"; some_guy = "George"; return 0; } </code></pre> Compile like this: $ g++ -O0 a.cpp -o a<p>Now, we can disassemble the "main" function to see exactly what is going on in the executable:<p><pre><code> $ objdump -d a a: file format elf32-i386 ... 08048614 &#60;main&#62;: 8048614: 55 push %ebp 8048615: 89 e5 mov %esp,%ebp 8048617: 83 e4 f0 and $0xfffffff0,%esp 804861a: 53 push %ebx 804861b: 83 ec 2c sub $0x2c,%esp 804861e: 8d 44 24 1f lea 0x1f(%esp),%eax 8048622: 89 04 24 mov %eax,(%esp) 8048625: e8 06 ff ff ff call 8048530 &#60;_ZNSaIcEC1Ev@plt&#62; 804862a: 8d 44 24 1f lea 0x1f(%esp),%eax 804862e: 89 44 24 08 mov %eax,0x8(%esp) 8048632: c7 44 24 04 80 87 04 movl $0x8048780,0x4(%esp) 8048639: 08 804863a: 8d 44 24 18 lea 0x18(%esp),%eax 804863e: 89 04 24 mov %eax,(%esp) 8048641: e8 ca fe ff ff call 8048510 &#60;_ZNSsC1EPKcRKSaIcE@plt&#62; 8048646: 8d 44 24 1f lea 0x1f(%esp),%eax 804864a: 89 04 24 mov %eax,(%esp) 804864d: e8 ce fe ff ff call 8048520 &#60;_ZNSaIcED1Ev@plt&#62; 8048652: c7 44 24 04 85 87 04 movl $0x8048785,0x4(%esp) ... </code></pre> In this case, we are interested in the following two lines:<p><pre><code> 8048632: c7 44 24 04 80 87 04 movl $0x8048780,0x4(%esp) </code></pre> and<p><pre><code> 8048652: c7 44 24 04 85 87 04 movl $0x8048785,0x4(%esp) </code></pre> 0x4(%esp) is the address on the stack of our 'some_guy' variable. We are moving an "immediate" (constant) value into that location. What does that immediate refer to? Again, let's find out experimentally:<p><pre><code> $ objdump -s -j .rodata a a: file format elf32-i386 Contents of section .rodata: 8048778 03000000 01000200 46726564 0047656f ........Fred.Geo 8048788 72676500 00000000 rge..... </code></pre> Notice that the address of "Fred" is 0x8048778 + 8 = 0x8048780, which is exactly the immediate value from the disassembled main function.<p>This means that our variable "some_guy" really is a pointer, and nothing more. The strings "Fred" and "George" are statically allocated in the data section of the binary, meaning they stick around indefinitely.