开发者

python call-by-reference on primitive types

I have experience with the imperative languages(C most often), and that's probably why I am confused in learning python.

I am trying to implement a simple bitwise flag-setter functions. So in C it would be like:

void set_state(int *state, int var, int set)
{
    (set)? *state |= var : *state &= ~var
}

int is_state(int *state, int var)
{
    return (*state & var > 0)
}

int *state refers to a state flag that I keep track of, and var is the flag that I would like to set or clear(decided by int set).

So I tried to 开发者_如何转开发do the same with Python 3.2 and...

def setState(nState, nVar, bSet):
    if bSet:
        nState |= nVar
    else:
        nState &= ~var
    print(nState)

Then I ran...

>>> state
1024
>>> nfirst
1
>>> nsecond
2
>>> setState(state, nfirst, True)
1025
>>> state
1024

debugger tells me that the value of 'state' got copied into nState and now nState got mutated itself(meaning it was changed in its own local scope). Wasn't python all about objects and everything-is-call-by-reference?

If so, why can't I see a side effect?

I am lost. Can someone explain what is going on here.


Python ints are immutable, so while a reference is being passed in, it is not possible to change the value of the int object. As you have seen, the local variable is a copy of the reference, so they are both bound to the same integer. However when you change the value of the local variable, a new integer object is created, and the local variable is rebound to the new object.

eg.

>>> def setState(nState, nVar, bSet):
...     print((nState, id(nState)))
...     if bSet:
...         nState |= nVar
...     else:
...         nState &= ~var
...     print((nState, id(nState)))
... 
>>> nState = 1024
>>> nState, id(nState)
(1024, 3077840368)
>>> setState(nState, 1, True)
(1024, 3077840368)          # local nState is bound to the same object
(1025, 3077840448)          # now the local nState is bound to the new `int` object

perhaps you can return nState from the function and assign it back, eg

>>> def setState(nState, nVar, bSet):
...     if bSet:
...         nState |= nVar
...     else:
...         nState &= ~var
...     return nState
... 
>>> nState = 1024
>>> nState = setState(nState, 1, True)
>>> nState
1025


Primitive types like numbers or strings aren't mutable, you cannot change a number even if it were passed by reference. When you changed the value you actually created a new number and assigned the reference to it to the nState variable.


http://mail.python.org/pipermail/tutor/2002-November/018828.html pretty much answers your question.

We can think of all "variable names" in Python as pointers to objects. In fact, that's pretty much what's going on.
[...]
The key here is that arithmetic in Python (or any manipulation on an "immutable" data type), does not modify the object, though: it dynamically constructs new objects:

Since lists, dicts and custom objects are usually mutable calling methods on them will not create a new object but modify the existing one, so you have the call-by-reference behaviour for those types you might actually expect.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜