我对命令式语言(最常见的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和一切都是通过引用调用?
如果是这样,为什么我不能看到副作用?
我迷路了。有人可以解释这里发生了什么。
答案 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行为。