【问题标题】:python call-by-reference on primitive typespython对原始类型的引用调用
【发布时间】:2011-09-24 01:25:40
【问题描述】:

我有使用命令式语言(最常使用 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 不是所有关于对象和一切都是通过引用调用的吗?

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

我迷路了。谁能解释一下这里发生了什么。

【问题讨论】:

  • “我有使用命令式语言的经验(最常见的是 C),这可能就是我在学习 python 时感到困惑的原因。”将一种语言的经验应用于另一种语言是一个坏主意。最好在开始每个语言教程时都空着脑袋,忘记所有您认为自己知道的以前的编程语言。

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


【解决方案1】:

Python ints 是不可变的,因此在传入引用时,无法更改 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

【讨论】:

  • 或者你可以创建一个类来表示一个“状态”,并通过替换它来“改变”它的一个属性。
【解决方案2】:

数字或字符串等原始类型是不可变的,即使数字是通过引用传递的,您也不能更改它。当您更改值时,您实际上创建了一个 new 数字并将对它的引用分配给 nState 变量。

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-05
      • 2013-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-11
      • 1970-01-01
      相关资源
      最近更新 更多