1

In the following example, a class is "automatically" passed "by reference" and a variable "by value":

class Q:
    def __init__(self, q):
        self.q = q

p = 42
q = Q(42)

def p_worker(p):
    p += 1
    return p

def q_worker(q):
    q.q += 1
    return q

print p is p_worker(p)
print q is q_worker(q)

The output is:

False
True

Why such discrepancy?

Rusty Shackleford
  • 1,111
  • 2
  • 14
  • 19
Sparkler
  • 2,581
  • 1
  • 22
  • 41
  • 3
    Generally, immutable objects are passed by value, and mutable objects are passed by reference. – TigerhawkT3 Jul 16 '15 at 02:28
  • @TigerhawkT3, the immutability of objects is pre determined or evaluated upon compilation? (the [example on Wikipedia](https://en.wikipedia.org/wiki/Immutable_object#Python) also returns True...) – Sparkler Jul 16 '15 at 02:38
  • 3
    @TigerhawkT3: That is incorrect. All objects are passed with the same semantics. It is just that with immutable objects, you cannot "take advantage" of passing by reference, because you can't do anything to alter the value you have a reference to. – BrenBarn Jul 16 '15 at 02:42
  • All the answers to ["How do I pass a variable by reference"](http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference) apply here too, so I voted to close this as a duplicate. – Cody Piersall Jul 16 '15 at 02:53
  • Okay, pass-by-reference is noticeable on mutable objects, but not noticeable on immutable objects. – TigerhawkT3 Jul 16 '15 at 02:54
  • Python only has pass-by-value, just like Java. – newacct Jul 16 '15 at 18:35

1 Answers1

4

They are always passed the same way. (This way is sometimes called "call-by-object" and sometimes called "call by value where the value is a reference". You can look it up in other questions on here.) The difference is in what the two objects are and what you are doing to them.

p += 1 essentially tells the p object to do += 1 on itself, and then assigns the result to the variable p. Integers cannot change their value, so all this does is add one to p and assign the result to p. p is a "bare name" (i.e., just a plain variable), so this just binds the number 43 to the variable p and that's it.

q.q += 1 tells q.q to do += 1on itself, and assigns the result to q.q. Again integers cannot change their value, so this adds one to q.q. But q.q is not a bare name; it is an attribute reference. So "assigning to q.q" means "ask the object q to assign this new value to its q. attribute". Since q can change its value (that is, the values of its attributes, it does).

The bottom line is that you can't assume the difference in your code is because the argument-passing semantics are different in the two cases. The argument-passing works the same. However, the objects you pass are different (one is an integer, and one is a Q), and those objects can handle operations like += in different ways. The discrepancy is not between two kinds of argument passing but between two different ways to handle +=.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384