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 += 1
on 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 +=
.