原始类型的python call-by-reference

时间:2011-06-28 06:43:16

标签: python pass-by-reference primitive-types

我对命令式语言(最常见的C)有经验,这可能就是我在学习python时感到困惑的原因。

我正在尝试实现一个简单的按位标志设置函数。所以在C中就像是:

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指的是我跟踪的状态标志,var是我想设置或清除的标志(由int set决定)。

所以我尝试用Python 3.2和...

做同样的事情
def setState(nState, nVar, bSet):
    if bSet:
        nState |= nVar
    else:
        nState &= ~var
    print(nState)

然后我跑了......

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

调试器告诉我'state'的值被复制到nState中,现在nState本身已经变异(意味着它在自己的本地范围内被更改)。是不是所有关于对象的python和一切都是通过引用调用?

如果是这样,为什么我不能看到副作用?

我迷路了。有人可以解释这里发生了什么。

3 个答案:

答案 0 :(得分:7)

Python int是不可变的,因此在传入引用时,无法更改int对象的值。如您所见,局部变量是引用的副本,因此它们都绑定到同一个整数。但是,当您更改局部变量的值时,将创建一个新的整数对象,并且局部变量将反弹到新对象。

例如

>>> 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

也许您可以从函数返回nState并将其分配回去,例如

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

答案 1 :(得分:4)

数字或字符串等原始类型不可变,即使通过引用传递,也无法更改数字。更改值后,您实际创建了一个 new 编号,并将其引用分配给nState变量。

答案 2 :(得分:1)

http://mail.python.org/pipermail/tutor/2002-November/018828.html几乎可以回答你的问题。

  

我们可以将Python中的所有“变量名称”视为对象的指针。   事实上,这正是发生的事情   [...]
  这里的关键是Python中的算术(或任何操作)   “不可变”数据类型),但不会修改对象:它是动态的   构造新对象:

由于列表,dicts和自定义对象通常是可变的,因此调用它们的方法不会创建新对象,而是修改现有对象,因此您可能会对实际可能期望的那些类型执行call-by-reference行为。